home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / exampleCode / games / IndiZone / oort / oort.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  62.0 KB  |  3,121 lines

  1. /*
  2.  * Copyright (C) 1994, Silicon Graphics, Inc.
  3.  * All Rights Reserved.
  4.  *
  5.  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  6.  * the contents of this file may not be disclosed to third parties, copied or
  7.  * duplicated in any form, in whole or in part, without the prior written
  8.  * permission of Silicon Graphics, Inc.
  9.  *
  10.  * RESTRICTED RIGHTS LEGEND:
  11.  * Use, duplication or disclosure by the Government is subject to restrictions
  12.  * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  13.  * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  14.  * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  15.  * rights reserved under the Copyright Laws of the United States.
  16.  */
  17. /*------------------------------------------------------------------------------
  18.  * oort.c    oort main routine.
  19.  *
  20.  * $Revision: 1.7 $ $Date: 1994/02/07 23:58:31 $ 
  21.  *
  22.  * Chris Fouts - April, 1993.
  23.  *
  24.  *----------------------------------------------------------------------------*/
  25.  
  26. #include <stdlib.h>
  27. #include <stdio.h>
  28. #include <string.h>
  29. #include <sys/param.h>
  30. #include <sys/types.h>
  31. #include <sys/stat.h>
  32. #include <fcntl.h>
  33. #include <bstring.h>
  34. #include <netinet/in.h>
  35. #include <netdb.h>
  36. #include <ctype.h>
  37. #include <arpa/inet.h>
  38. #include <gl/device.h>
  39.  
  40. #include <pf.h>
  41.  
  42. #include "oort.h"
  43. #include "configure.h"
  44. #include "load.h"
  45. #include "gameio.h"
  46. #include "dashboard.h"
  47. #include "background.h"
  48. #include "vehicle.h"
  49. #include "input.h"
  50. #include "radar.h"
  51. #include "text.h"
  52. #include "validate.h"
  53. #include "multicast.h"
  54. #include "explosion.h"
  55. #include "sound.h"
  56.  
  57. #define    LASER_MASK    0x08
  58.  
  59. pfLight        *Sun;
  60.  
  61. Object        starObj ;
  62. Object        helpObj ;
  63.  
  64. char        *basename = "oort" ;
  65. char        playerName[NAMELEN] ;
  66. pfVec3        groundColor =    { 0.54f, 0.50f, 0.36f } ;
  67. pfVec3        vehicleColor ;
  68. pfVec3        teamColor[N_TEAMS] = {
  69.             { 1.00f, 1.00f, 1.00f },
  70.             { 1.00f, 0.25f, 0.25f },
  71.             { 0.25f, 1.00f, 0.25f },
  72.             { 0.25f, 0.25f, 1.00f },
  73.             } ;
  74. static char    *defaultConfigText[6] = {
  75.             "terrainColor:   0.54 0.50 0.36\n",
  76.             "textLines:      12\n",
  77.             "teamColorA:     1.00 1.00 1.00\n",
  78.             "teamColorB:     1.00 0.25 0.25\n",
  79.             "teamColorC:     0.25 1.00 0.25\n",
  80.             "teamColorD:     0.25 0.25 1.00\n",
  81.             } ;
  82.  
  83. static unsigned short    cursorBitMap1[] = {
  84.                 0xc003, 0xe007, 0x700e, 0x381c,
  85.                 0x1c38, 0x0e70, 0x0660, 0x0000,
  86.                 0x0000, 0x0660, 0x0e70, 0x1c38,
  87.                 0x381c, 0x700e, 0xe007, 0xc003,
  88.                 } ;
  89. static unsigned short    cursorBitMap2[] = {
  90.                 0x0000, 0x4002, 0x2004, 0x1008,
  91.                 0x0810, 0x0420, 0x0240, 0x0000,
  92.                 0x0000, 0x0240, 0x0420, 0x0810,
  93.                 0x1008, 0x2004, 0x4002, 0x0000,
  94.  
  95.                 0xc003, 0xa005, 0x500a, 0x2814,
  96.                 0x1428, 0x0a50, 0x0420, 0x0000,
  97.                 0x0000, 0x0420, 0x0a50, 0x1428,
  98.                 0x2814, 0x500a, 0xa005, 0xc003,
  99.                 } ;
  100.  
  101. typedef void    (*MoveFunction)( void ) ;
  102.  
  103. PacketFunction        readPackets ;
  104. PacketFunction        writePackets ;
  105. MoveFunction        moveMe ;
  106.  
  107. float        frameRate = 15.0f ;
  108. int        initialVol = 11 ;
  109. int        showHelp = 0 ;
  110. int        selfStatus ;
  111. int        newSelfStatus ;
  112. int        networking ;
  113. int        nTextLines = 12 ;
  114. int        landing = 0 ;
  115. int        selfDestruct = 0 ;
  116. float        selfDestructTime ;
  117. float        selfDestructAlarmTime ;
  118. Motion        motion ;
  119. GeoFont        *helvFont ;
  120. GeoFont        *helpFont ;
  121. ViewPort    headingVP ;
  122. ViewPort    radarVP ;
  123. ViewPort    indicatorVP ;
  124. Wheel        wheel[3] ;
  125. Player        player[MAXPLAYERS] ;
  126. int        activity[MAXPLAYERS] ;
  127. pfDCS        *trike[MAXPLAYERS] ;
  128. pfGroup        *trikeSwitch[MAXPLAYERS] ;
  129. pfGroup        *shield ;
  130. pfGroup        *pShield[MAXPLAYERS] ;
  131. pfGroup        *vehicle[N_TEAMS] ;
  132. pfMatrix    playerMatrix[MAXPLAYERS] ;
  133. float        deadTime[MAXPLAYERS] ;
  134. pfVec3        velocity[MAXPLAYERS] ;
  135. pfVec3        acceleration[MAXPLAYERS] ;
  136. pfMatrix    selfMatrix ;
  137. pfVec3        up ;                /* Up rel to vehicle. */
  138. pfVec3        ahead ;                /* Ahead rel to vehicle. */
  139. pfVec3        right ;                /* Right rel to vehicle. */
  140. pfVec3        worldUp ;            /* Up rel to oort. */
  141. float        speed ;
  142. float        shields ;
  143. float        power ;
  144. float        laser ;
  145. float        cloak ;
  146. int        cloakOn ;
  147. float        laserCharge ;
  148. float        shieldRegenRate ;
  149. float        laserRegenRate ;
  150. float        cloakRegenRate ;
  151. float        gameTime ;    /* elapsed time for entire game */
  152. float        eTime ;        /* elapsed time since last frame */
  153. float        idleStartTime = 0.0f ;
  154. int        stayInProgram = 1 ;
  155. int        showStats = 0 ;
  156. int        leftMouseHit = 0 ;
  157. int        middleMouseDown = 0 ;
  158. int        rightMouseHit = 0 ;
  159. int        timeToLive = NG_DEFAULT_TTL ;
  160. float        mouseX ;
  161. float        mouseY ;
  162. float        pickX ;
  163. float        pickY ;
  164. float        latitude = 0.0f ;
  165. float        longitude = 0.0f ;
  166. int        numberPlayers = 1 ;
  167. float        mvOverlayH = 1.0f ;
  168. float        mvOverlayW = 1.0f ;
  169. float        pitch ;
  170. float        roll ;
  171. int        inFd = -1 ;
  172. int        outFd = -1 ;
  173. char        *inName = NULL ;
  174. char        *outName = NULL ;
  175. int        demoMode = 0 ;
  176.  
  177. static pfChannel    *mainChan ;
  178. static pfChannel    *diagChan ;
  179. static pfGeoSet        *starGSet ;
  180. static pfGroup        *terrain ;
  181. static pfGroup        *vehicleGroup ;
  182. static pfGroup        *terrainAndVehicles ;
  183. static pfScene        *mainScene ;
  184. static pfSphere        *vehicleBoundingSphere ;
  185. static pfBox        hitBox ;
  186. static pfMatrix        hitMatrix ;
  187.  
  188. static int        trikeHit ;
  189. static int        checkTrike ;
  190.  
  191. extern int        roidZoom ;
  192. extern int        debugOn ;
  193. extern float        topSpeed ;
  194. extern float        shieldFactor ;
  195. extern float        laserFactor ;
  196. extern float        engineRate ;
  197. extern float        cloakRate ;
  198. extern float        solarRate ;
  199. extern ViewPort        mainVP ;
  200. extern int        terrainTextured ;
  201.  
  202.  
  203.  
  204. /* BEGIN PROTOTYPES -S oort.c */
  205. static void     checkGraphicsHw( void ) ;
  206. static void     checkMinReqs( void ) ;
  207. static int      compareScores( const void *p1, const void *p2 ) ;
  208. static void     CullDiagChannel( pfChannel *channel, void *data ) ;
  209. static void     demoMainLoop( void ) ;
  210. static void     demoPostProcessPlayers( void ) ;
  211. static void     displayHelp( void ) ;
  212. static void     distributePower( void ) ;
  213. static void     doPick( pfNode *root, long mode, long mask, pfHit **hits[] ) ;
  214. static void     drawMainChannel( pfChannel *channel, void *data ) ;
  215. static void     drawOrbitalFortressStrikes( void ) ;
  216. static void     drawPitchRollIndicator( void ) ;
  217. static void     drawStaticDisplay( void ) ;
  218. static void     drawStaticScreen( pfChannel *channel, void *data ) ;
  219. static void     drawTitle( void ) ;
  220. static void     fireLaser( void ) ;
  221. static long     fireLaserPostTravCB( pfTraverser *trav, void *data ) ;
  222. static long     fireLaserPreTravCB( pfTraverser *trav, void *data ) ;
  223. static void     getLatLong( void ) ;
  224. static void     groundIntersectionSetup( pfGroup *root ) ;
  225. static void     initCursor( void ) ;
  226. static void     initEnemies( void ) ;
  227. static void     initSelf( void ) ;
  228. static void     initShield( void ) ;
  229. static void     initStuff( void ) ;
  230. static void     loadCustom( void ) ;
  231. static void     mainLoop( void ) ;
  232. static Object   makeHelpOverlay( void ) ;
  233. static void     moveArgs( int argc, char **argv, int start, int n ) ;
  234. static void     noConfigFile( char *name ) ;
  235. static void     openPipe( pfPipe *p ) ;
  236. static void     parseArgs( int *argc, char **argv ) ;
  237. static long     pickDiscFunc( pfHit *hit ) ;
  238. static int      pickLandingSite( pfVec3 landingSite ) ;
  239. static void     pickPlayer( void ) ;
  240. static void     postProcessPlayers( void ) ;
  241. static int      readColor( char *s, pfVec3 v ) ;
  242. static void     repaintCompass( void ) ;
  243. static void     setupChannels( pfPipe *p ) ;
  244. static void     updateViewGround( void ) ;
  245. static void     updateViewInOrbit( void ) ;
  246. static void     usage( void ) ;
  247. static void     vecMultMatInPlace( pfVec4 v, pfMatrix m ) ;
  248. /* END PROTOTYPES -S oort.c */
  249.  
  250.  
  251.  
  252. #define    HALFTONE_PATTERN    1
  253. static unsigned short    halftone[] = {
  254.                 0xaaaa, 0x5555, 0xaaaa, 0x5555,
  255.                 0xaaaa, 0x5555, 0xaaaa, 0x5555,
  256.                 0xaaaa, 0x5555, 0xaaaa, 0x5555,
  257.                 0xaaaa, 0x5555, 0xaaaa, 0x5555,
  258.                 } ;
  259. #define    STATIC_PATTERN_0    2
  260. #define    STATIC_PATTERN_1    3
  261. #define    STATIC_PATTERN_2    4
  262. static unsigned short    staticPattern[3][16] = {
  263.                     {
  264.                     0xfc00, 0xfc00, 0x003f, 0x003f,
  265.                     0x0fc0, 0x0fc0, 0xf003, 0xf003,
  266.                     0x00fc, 0x00fc, 0x3f00, 0x3f00,
  267.                     0xc00f, 0xc00f, 0x03f0, 0x03f0,
  268.                     },
  269.                     {
  270.                     0x03f0, 0x03f0, 0xfc00, 0xfc00,
  271.                     0x003f, 0x003f, 0x0fc0, 0x0fc0,
  272.                     0xf003, 0xf003, 0x00fc, 0x00fc,
  273.                     0x3f00, 0x3f00, 0xc00f, 0xc00f,
  274.                     },
  275.                     {
  276.                     0xc00f, 0xc00f, 0x03f0, 0x03f0,
  277.                     0xfc00, 0xfc00, 0x003f, 0x003f,
  278.                     0x0fc0, 0x0fc0, 0xf003, 0xf003,
  279.                     0x00fc, 0x00fc, 0x3f00, 0x3f00,
  280.                     },
  281.                 } ;
  282. static long    staticColor[] = { 0x00404040, 0x00808080, 0x00c0c0c0 } ;
  283.  
  284.  
  285.  
  286. /*------------------------------------------------------------------------------
  287.  * Print usage command.
  288.  *----------------------------------------------------------------------------*/
  289. static void
  290. usage(
  291.     void
  292.     )
  293. {
  294.     fprintf( stderr, "Usage: %s [-h] [-i in_file] [-o out_file] "
  295.         "[-n player_name] [-T ttl]\n", basename ) ;
  296.     fprintf( stderr, "Usage: %s [-d demo_file]\n", basename ) ;
  297.     endProgram( 1 ) ;
  298. }
  299.  
  300.  
  301.  
  302. /*------------------------------------------------------------------------------
  303.  * Main routine.
  304.  *----------------------------------------------------------------------------*/
  305. void
  306. main(
  307.     int    argc,
  308.     char    **argv
  309.     )
  310. {
  311.     int    i ;
  312.  
  313.     /*
  314.      * Load custom options from ~/.oortrc.
  315.      */
  316.     loadCustom() ;
  317.  
  318.     /*
  319.      * Parse command line arguments.
  320.      */
  321.     parseArgs( &argc, argv ) ;
  322.  
  323.     /*
  324.      * Check for minimum system requirements.
  325.      */
  326.     checkMinReqs() ;
  327.  
  328.     /*
  329.      * Initialize Performer
  330.      */
  331.     pfInit();
  332.  
  333.     /*
  334.      * Configure MP mode to use a single process.
  335.      */
  336.     pfMultiprocess( PFMP_APPCULLDRAW ) ;
  337.     pfConfig();
  338.  
  339.     pfNotifyLevel( PFNFY_FATAL ) ;
  340.     mainScene = pfNewScene();
  341.  
  342.     initGeoStates() ;
  343.  
  344.     terrainAndVehicles = pfNewGroup() ;
  345.     pfAddChild( mainScene, terrainAndVehicles ) ;
  346.  
  347.     initStuff() ;
  348.  
  349.     if( ( terrain = loadOortTerrain( "oort.data" ) ) == NULL )
  350.     {
  351.         endProgram( 1 ) ;
  352.     }
  353.     pfAddChild( terrainAndVehicles, terrain ) ;
  354.  
  355.     groundIntersectionSetup( terrain ) ;
  356.  
  357.     vehicleGroup = pfNewGroup() ;
  358.     pfAddChild( terrainAndVehicles, vehicleGroup ) ;
  359.     pfNodeTravMask( vehicleGroup, PFTRAV_ISECT, LASER_MASK | VEHICLE_MASK,
  360.             PFTRAV_SELF | PFTRAV_IS_CACHE, PF_SET ) ;
  361.  
  362.     for( i = 0 ; i < N_TEAMS ; i++ )
  363.     {
  364.         PFCOPY_VEC3( vehicleColor, teamColor[i] ) ;
  365.         if( ( vehicle[i] = loadOortVehicle( "vehicle.data" ) ) == NULL )
  366.         {
  367.             endProgram( 1 ) ;
  368.         }
  369.     }
  370.  
  371.     initShield() ;
  372.  
  373.     initExplosion() ;
  374.  
  375.     pfPhase( PFPHASE_FLOAT ) ;
  376.     pfFrameRate( frameRate ) ;
  377.  
  378.     initSelf() ;
  379.  
  380.     checkGraphicsHw() ;
  381.  
  382.     pfInitClock( 0.0 );
  383.  
  384.     if( demoMode )
  385.         demoMainLoop() ;
  386.     else
  387.         mainLoop() ;
  388.  
  389.     if( networking )
  390.         ngSendQuitPacket() ;
  391.  
  392.     endProgram( 0 ) ;
  393. }
  394.  
  395.  
  396.  
  397. /*------------------------------------------------------------------------------
  398.  * Open and initialize the pipe.
  399.  *----------------------------------------------------------------------------*/
  400. static void
  401. openPipe(
  402.     pfPipe *p
  403.     )
  404. {
  405.     /*
  406.      * Create a window.
  407.      */
  408.     foreground() ;
  409.     minsize( 400, 300 ) ;
  410.     winopen( "oort" ) ;
  411.  
  412.     pfInitGfx( p ) ;
  413.  
  414.     /*
  415.      * Queue up devices.
  416.      */
  417.     setDevices() ;
  418.  
  419.     /*
  420.      * Set the cursor.
  421.      */
  422.     initCursor() ;
  423.  
  424.     /*
  425.      * Determine window's position.
  426.      */
  427.     getWindowPosition() ;
  428.  
  429.     helvFont = loadFont( "h.oort" ) ;
  430.     setFontSize( helvFont, 0.2f ) ;
  431.  
  432.     pfBasicState() ;
  433.     drawTitle() ;
  434.     swapbuffers() ;
  435.  
  436.     /*
  437.      * Create a light source.
  438.      */
  439.     Sun = pfNewLight( pfGetSharedArena() ) ;
  440.     pfLightPos( Sun, 0.0f, -1.0f, 0.0f, 0.0f ) ;
  441.     pfApplyLModel( pfNewLModel( pfGetSharedArena() ) ) ;
  442.     pfLightOn( Sun ) ;
  443. }
  444.  
  445.  
  446.  
  447. /*------------------------------------------------------------------------------
  448.  * Channel draw callback - clear, reset sun, and draw.
  449.  *----------------------------------------------------------------------------*/
  450. static void
  451. drawMainChannel(
  452.     pfChannel    *channel,
  453.     void        *data
  454.     )
  455. {
  456.     float    f ;
  457.  
  458.     /* erase framebuffer and draw Earth-Sky model */
  459.     pfClearChan( channel ) ;
  460.  
  461.     /*
  462.      * Get input.
  463.      */
  464.     grabInput() ;
  465.  
  466.     /*
  467.      * Draw stars.
  468.      */
  469.     pfPushMatrix() ;
  470.     translate( motion.cg[0], motion.cg[1], motion.cg[2] ) ;
  471.     callobj( starObj ) ;
  472.     pfPopMatrix() ;
  473.     
  474.     /*
  475.      * Determine world up vector.
  476.      */
  477.     PFCOPY_VEC3( worldUp, motion.cg ) ;
  478.     pfNormalizeVec3( worldUp ) ;
  479.  
  480.     pfLightPos(Sun, 0.0f, -1.0f, 0.0f, 0.0f);
  481.     if( worldUp[1] < 0.0f )
  482.     {
  483.         pfLightAmbient( Sun, -0.60f*worldUp[1], -0.55f*worldUp[1],
  484.                 -0.40f*worldUp[2] ) ;
  485.     }
  486.     else
  487.     {
  488.         pfLightAmbient( Sun, 0.0f, 0.0f, 0.0f ) ;
  489.     }
  490.     pfLightOn( Sun ) ;
  491.  
  492.     /*
  493.      * Invoke Performer draw-processing for this frame.
  494.      */
  495.     pfDraw() ;
  496.  
  497.     if( player[SELF].status & ( OORT_ST_SHIELDS | OORT_ST_IDLE_HIT ) )
  498.     {
  499.         setpattern( HALFTONE_PATTERN ) ;
  500.         cpack( 0x00ffff00 ) ;
  501.         clear() ;
  502.         setpattern( 0 ) ;
  503.     }
  504.  
  505.     if( showStats )
  506.         pfDrawChanStats( channel ) ;
  507.  
  508.     pfPushState() ;
  509.     pfBasicState() ;
  510.  
  511.     drawOrbitalFortressStrikes() ;
  512.  
  513.     drawPitchRollIndicator() ;
  514.  
  515.     pfPopState() ;
  516. }
  517.  
  518.  
  519.  
  520. /*------------------------------------------------------------------------------
  521.  * Draw the pitch/roll indicator in the main view.
  522.  *----------------------------------------------------------------------------*/
  523. static void
  524. drawPitchRollIndicator(
  525.     void
  526.     )
  527. {
  528.     float    ndr ;
  529.     float    ndu ;
  530.     float    nda ;
  531.     pfVec3    n ;
  532.     pfVec2    a ;
  533.     pfVec2    b ;
  534.     pfVec2    c ;
  535.  
  536.     pfPushIdentMatrix() ;
  537.     pushviewport() ;
  538.     ortho2( -mvOverlayW, mvOverlayW, -mvOverlayH, mvOverlayH ) ;
  539.     zfunction( ZF_ALWAYS ) ;
  540.     zwritemask( 0x0 ) ;
  541.  
  542.     pfShadeModel( PFSM_FLAT ) ;
  543.  
  544.     cpack( 0x0000ffff ) ;
  545.     rect( -0.2f, -0.2f, 0.2f, 0.2f ) ;
  546.  
  547.     scrmask( indicatorVP.left, indicatorVP.right, indicatorVP.bottom,
  548.         indicatorVP.top ) ;
  549.     if( selfStatus == OORT_ST_IN_ORBIT )
  550.     {
  551.         bgnline() ;
  552.             c[0] = 0.0f ;
  553.             c[1] = 0.2f ;
  554.             v2f( c ) ;
  555.             c[1] = -0.2f ;
  556.             v2f( c ) ;
  557.         endline() ;
  558.         bgnline() ;
  559.             c[0] = 0.2f ;
  560.             c[1] = 0.0f ;
  561.             v2f( c ) ;
  562.             c[0] = -0.2f ;
  563.             v2f( c ) ;
  564.         endline() ;
  565.     }
  566.     else
  567.     {
  568.         PFCOPY_VEC3( n, motion.cg ) ;
  569.         pfNormalizeVec3( n ) ;
  570.  
  571.         nda = PFDOT_VEC3( n, ahead ) ;
  572.         ndr = PFDOT_VEC3( n, right ) ;
  573.         ndu = PFDOT_VEC3( n, up ) ;
  574.  
  575.         pitch = pfArcTan2( nda, ndu ) ;
  576.         if( nda < -0.99999f || nda > 0.99999f )
  577.         {
  578.             roll = 0.0f ;
  579.         }
  580.         else
  581.         {
  582.             roll = pfArcTan2( ndr, ndu ) ;
  583.         }
  584.  
  585.         PFSET_VEC2( a, 0.0f, 0.2f * pitch / -45.0f ) ;
  586.         if( ndu != 0.0f )
  587.         {
  588.             PFSET_VEC2( b, -0.2f, 0.2f * ndr / ndu ) ;
  589.             PFADD_VEC2( c, a, b ) ;
  590.             bgnline() ;
  591.                 v2f( c ) ;
  592.                 PFSUB_VEC2( c, a, b ) ;
  593.                 v2f( c ) ;
  594.             endline() ;
  595.         }
  596.         else
  597.         {
  598.             bgnline() ;
  599.                 c[0] = 0.0f ;
  600.                 c[1] = 0.2f ;
  601.                 v2f( c ) ;
  602.                 c[1] = -0.2f ;
  603.                 v2f( c ) ;
  604.             endline() ;
  605.         }
  606.  
  607.         if( selfStatus == OORT_ST_ON_GROUND &&
  608.             ( ABS( roll ) > 80.0f || ABS( pitch ) > 80.0f ) )
  609.         {
  610.             postNewMessage( "Overturned." ) ;
  611.             blowUpSelf( 0 ) ;
  612.         }
  613.     }
  614.     zfunction( ZF_LEQUAL ) ;
  615.     zwritemask( 0xffffffff ) ;
  616.  
  617.     popviewport() ;
  618.  
  619.     if( showHelp )
  620.     {
  621.  
  622.         cpack( 0x0000ff00 ) ;
  623.         callobj( helpObj ) ;
  624.  
  625.     }
  626.     pfPopMatrix() ;
  627. }
  628.  
  629.  
  630.  
  631. /*------------------------------------------------------------------------------
  632.  * Channel cull callback - do nothing.
  633.  *----------------------------------------------------------------------------*/
  634. static void
  635. CullDiagChannel(
  636.     pfChannel    *channel,
  637.     void        *data
  638.     )
  639. {
  640.     /* ARGSUSED */
  641. }
  642.  
  643.  
  644.  
  645. /*------------------------------------------------------------------------------
  646.  * Compute the new view.
  647.  *----------------------------------------------------------------------------*/
  648. static void
  649. updateViewInOrbit(
  650.     void
  651.     )
  652. {
  653.     float        st ;
  654.     float        ct ;
  655.     float        sp ;
  656.     float        cp ;
  657.     float        r = (float)(ASTEROID_RADIUS * 4.0f) ;
  658.     pfVec3        hpr ;
  659.     pfMatrix    m ;
  660.     pfVec3        v ;
  661.     static int    mode = 0 ;
  662.     static float    startX ;
  663.     static float    startY ;
  664.     static float    zoomFactor = 1.0f ;
  665.  
  666.     if( roidZoom == 1 )
  667.     {
  668.         zoomFactor = 1.05f * zoomFactor ;
  669.     }
  670.     else if( roidZoom == 2 )
  671.     {
  672.         zoomFactor = zoomFactor / 1.05f ;
  673.     }
  674.     r *= zoomFactor ;
  675.  
  676.     /*
  677.      * Rotate asteroid if middle mouse down.
  678.      */
  679.     if( middleMouseDown )
  680.     {
  681.         if( mode )
  682.         {
  683.             longitude += ( mouseX - startX ) * 180.0f * 1.0f ;
  684.             if( longitude < -180.0f )
  685.             {
  686.                 longitude += 360.0f ;
  687.             }
  688.             else if( longitude > 180.0f )
  689.             {
  690.                 longitude -= 360.0f ;
  691.             }
  692.             latitude += ( mouseY - startY ) * 90.0f * 1.0f ;
  693.             if( latitude < -90.0f )
  694.             {
  695.                 latitude = -90.0f ;
  696.             }
  697.             else if( latitude > 90.0f )
  698.             {
  699.                 latitude = 90.0f ;
  700.             }
  701.         }
  702.         startX = mouseX ;
  703.         startY = mouseY ;
  704.     }
  705.     mode = middleMouseDown ;
  706.     pfSinCos( longitude, &st, &ct ) ;
  707.     pfSinCos( latitude, &sp, &cp ) ;
  708.     PFSET_VEC3( hpr, longitude, -latitude, 0.0f ) ;
  709.     PFSET_VEC3( motion.cg, r*st*cp, -r*ct*cp, r*sp ) ;
  710.     pfChanView( mainChan, motion.cg, hpr ) ;
  711.  
  712.     if( leftMouseHit && pickLandingSite( motion.cg ) )
  713.     {
  714.         landing = 1 ;
  715.  
  716.         pfNormalizeVec3( motion.cg ) ;
  717.         if( motion.cg[2] < -0.9999f )
  718.         {
  719.             latitude = -90.0f ;
  720.             longitude = 0.0f ;
  721.         }
  722.         else if( 0.9999f < motion.cg[2] )
  723.         {
  724.             latitude = 90.0f ;
  725.             longitude = 0.0f ;
  726.         }
  727.         else
  728.         {
  729.             latitude = pfArcSin( motion.cg[2] ) ;
  730.             longitude = pfArcTan2( motion.cg[0], -motion.cg[1] ) ;
  731.         }
  732.  
  733.         pfSinCos( longitude, &st, &ct ) ;
  734.         pfSinCos( latitude, &sp, &cp ) ;
  735.  
  736.         postNewMessage( "Landing at %.1f, %.1f", latitude, longitude ) ;
  737.  
  738.         PFSCALE_VEC3( motion.cg, (float)(1.1f*ASTEROID_RADIUS),
  739.                 motion.cg ) ;
  740.         PFSET_VEC3( motion.vel, 0.0f, 0.0f, 0.0f ) ;
  741.         PFCOPY_VEC3( player[SELF].xyz, motion.cg ) ;
  742.  
  743.         PFSET_VEC3( wheel[FRONT_WHEEL].vel, 0.0f, 0.0f, 0.0f ) ;
  744.         PFSET_VEC3( wheel[RREAR_WHEEL].vel, 0.0f, 0.0f, 0.0f ) ;
  745.         PFSET_VEC3( wheel[LREAR_WHEEL].vel, 0.0f, 0.0f, 0.0f ) ;
  746.         wheel[FRONT_WHEEL].inAir = 1 ;
  747.         wheel[RREAR_WHEEL].inAir = 1 ;
  748.         wheel[LREAR_WHEEL].inAir = 1 ;
  749.  
  750.         selfStatus = OORT_ST_ON_GROUND ;
  751.  
  752.         PFSET_VEC3( right, ct, st, 0.0f ) ;
  753.         PFSET_VEC3( up, st*cp, -ct*cp, sp ) ;
  754.         pfCrossVec3( ahead, up, right ) ;
  755.  
  756.         updateWheels() ;
  757.  
  758.         updateViewGround() ;
  759.     }
  760.     leftMouseHit = 0 ;
  761. }
  762.  
  763.  
  764.  
  765. /*------------------------------------------------------------------------------
  766.  * Compute the new view.
  767.  *----------------------------------------------------------------------------*/
  768. static void
  769. updateViewGround(
  770.     void
  771.     )
  772. {
  773.     pfVec3        u ;
  774.     pfCoord        view ;
  775.     pfMatrix    m ;
  776.     float        s ;
  777.     float        c ;
  778.     float        d ;
  779.  
  780.     PFCOPY_VEC3( player[SELF].xyz, motion.cg ) ;
  781.     ADDSCALE_VEC3( u, motion.cg, CAR_HEIGHT, up );
  782.  
  783.     selfMatrix[0][0] = right[0] ;
  784.     selfMatrix[0][1] = right[1] ;
  785.     selfMatrix[0][2] = right[2] ;
  786.  
  787.     selfMatrix[1][0] = ahead[0] ;
  788.     selfMatrix[1][1] = ahead[1] ;
  789.     selfMatrix[1][2] = ahead[2] ;
  790.  
  791.     selfMatrix[2][0] = up[0] ;
  792.     selfMatrix[2][1] = up[1] ;
  793.     selfMatrix[2][2] = up[2] ;
  794.  
  795.     selfMatrix[3][0] = u[0] ;
  796.     selfMatrix[3][1] = u[1] ;
  797.     selfMatrix[3][2] = u[2] ;
  798.  
  799.     selfMatrix[0][3] = 0.0f ;
  800.     selfMatrix[1][3] = 0.0f ;
  801.     selfMatrix[2][3] = 0.0f ;
  802.     selfMatrix[3][3] = 1.0f ;
  803.  
  804.     /*
  805.      * Check for bug workaround in pre-Performer_1.2.
  806.      */
  807.     if( selfMatrix[1][2] > 0.999999 )
  808.     {
  809.         selfMatrix[1][2] = 1.0f ;
  810.     }
  811.     else if( selfMatrix[1][2] < -0.999999 )
  812.     {
  813.         selfMatrix[1][2] = -1.0f ;
  814.     }
  815.  
  816.     pfChanViewMat( mainChan, selfMatrix ) ;
  817. }
  818.  
  819.  
  820.  
  821. /*------------------------------------------------------------------------------
  822.  * Initialize own player structure.
  823.  *----------------------------------------------------------------------------*/
  824. static void
  825. initSelf(
  826.     void
  827.     )
  828. {
  829.     player[SELF].magic = OORT_PLAYER ;
  830.     player[SELF].key   = 0 ;
  831.     player[SELF].score = 0 ;
  832.     player[SELF].team  = 0 ;
  833.  
  834.     PFSET_VEC3( motion.cg, 0.0f, (float)(-1.1f * ASTEROID_RADIUS), 0.0f ) ;
  835.     PFSET_VEC3( motion.vel, 0.0f, 0.0f, 0.0f ) ;
  836.  
  837.     PFSET_VEC3( wheel[FRONT_WHEEL].vel, 0.0f, 0.0f, 0.0f ) ;
  838.     PFSET_VEC3( wheel[RREAR_WHEEL].vel, 0.0f, 0.0f, 0.0f ) ;
  839.     PFSET_VEC3( wheel[LREAR_WHEEL].vel, 0.0f, 0.0f, 0.0f ) ;
  840.     wheel[FRONT_WHEEL].inAir = 1 ;
  841.     wheel[RREAR_WHEEL].inAir = 1 ;
  842.     wheel[LREAR_WHEEL].inAir = 1 ;
  843.  
  844.     PFSET_VEC3( ahead, 1.0f, 0.0f, 0.0f ) ;
  845.     PFSET_VEC3( right, 0.0f, 0.0f, -1.0f ) ;
  846.     PFSET_VEC3( up, 0.0f, -1.0f, 0.0f ) ;
  847.  
  848.     updateWheels() ;
  849.  
  850.     reset() ;
  851. }
  852.  
  853.  
  854.  
  855. /*------------------------------------------------------------------------------
  856.  * Set up traversal mask for collision.
  857.  *----------------------------------------------------------------------------*/
  858. static void
  859. groundIntersectionSetup(
  860.     pfGroup    *root
  861.     )
  862. {
  863.     int    mode ;
  864.  
  865.     pfNodeTravMask( root, PFTRAV_ISECT, LASER_MASK | GROUND_MASK,
  866.             PFTRAV_SELF | PFTRAV_DESCEND | PFTRAV_IS_CACHE,
  867.             PF_SET ) ;
  868. }
  869.  
  870.  
  871.  
  872. /*------------------------------------------------------------------------------
  873.  * Set up main channel and diagnostic channels.
  874.  *----------------------------------------------------------------------------*/
  875. static void
  876. setupChannels(
  877.     pfPipe    *p
  878.     )
  879. {
  880.     mainChan = pfNewChan( p ) ;
  881.     pfChanViewport( mainChan, 0.0f, 1.0f, MAIN_VIEW_BOTTOM, 1.0f ) ;
  882.     pfChanNearFar( mainChan, 0.1f, (float)(5.0f*ASTEROID_RADIUS) ) ;
  883.     pfChanFOV( mainChan, 60.0f, -1.0f ) ;
  884.     setMainDrawFunction() ;
  885.  
  886.     diagChan = pfNewChan( p ) ;
  887.     pfChanViewport( diagChan, 0.0f, 1.0f, 0.0f, MAIN_VIEW_BOTTOM ) ;
  888.     pfChanDrawFunc( diagChan, drawDashboardChannel ) ;
  889.     pfChanCullFunc( diagChan, CullDiagChannel ) ;
  890. }
  891.  
  892.  
  893.  
  894. /*------------------------------------------------------------------------------
  895.  * Determine the latitude and longitude.
  896.  *----------------------------------------------------------------------------*/
  897. static void
  898. getLatLong(
  899.     void
  900.     )
  901. {
  902.     pfVec3    v ;
  903.  
  904.     PFCOPY_VEC3( v, motion.cg ) ;
  905.     pfNormalizeVec3( v ) ;
  906.  
  907.     latitude = pfArcSin( v[2] ) ;
  908.  
  909.     if( v[2] != 1.0f )
  910.     {
  911.         longitude = pfArcTan2( v[0], -v[1] ) ;
  912.     }
  913.     else
  914.     {
  915.         longitude = 0.0f ;
  916.     }
  917. }
  918.  
  919.  
  920.  
  921. /*------------------------------------------------------------------------------
  922.  * Parse command line arguments.
  923.  *----------------------------------------------------------------------------*/
  924. static void
  925. parseArgs(
  926.     int    *argc,
  927.     char    **argv
  928.     )
  929. {
  930.     int    i ;
  931.     int    key ;
  932.     int    argn = 0 ;
  933.  
  934.     if( ( basename = strrchr( argv[0], '/' ) ) == NULL )
  935.         basename = argv[0] ;
  936.     else
  937.         basename++ ;
  938.  
  939.     for( i = 1 ; i < *argc ; i++ )
  940.     {
  941.         argn++ ;
  942.         if( argv[i][0] == '-' )
  943.         {
  944.             if( !strcmp( argv[i]+1, "i" ) )
  945.             {
  946.                 if( inName != NULL )
  947.                     usage() ;
  948.                 inName = argv[i+1] ;
  949.                 moveArgs( *argc, argv, i, 2 ) ;
  950.                 *argc -= 2 ;
  951.                 i-- ;
  952.             }
  953.             else if( !strcmp( argv[i]+1, "d" ) )
  954.             {
  955.                 if( inName != NULL || outName != NULL )
  956.                     usage() ;
  957.                 inName = argv[i+1] ;
  958.                 moveArgs( *argc, argv, i, 2 ) ;
  959.                 *argc -= 2 ;
  960.                 demoMode = 1 ;
  961.                 i-- ;
  962.             }
  963.             else if( !strcmp( argv[i]+1, "T" ) )
  964.             {
  965.                 timeToLive = (int)atol( argv[i+1] ) ;
  966.                 moveArgs( *argc, argv, i, 2 ) ;
  967.                 *argc -= 2 ;
  968.                 i-- ;
  969.             }
  970.             else if( !strcmp( argv[i]+1, "o" ) )
  971.             {
  972.                 if( demoMode )
  973.                     usage() ;
  974.                 outName = argv[i+1] ;
  975.                 moveArgs( *argc, argv, i, 2 ) ;
  976.                 *argc -= 2 ;
  977.                 i-- ;
  978.             }
  979.             else if( !strcmp( argv[i]+1, "n" ) )
  980.             {
  981.                 strncpy( playerName, argv[i+1],
  982.                     sizeof( playerName ) - 1 ) ;
  983.                 moveArgs( *argc, argv, i, 2 ) ;
  984.                 *argc -= 2 ;
  985.                 i-- ;
  986.             }
  987.             else if( !strcmp( argv[i]+1, "h" ) )
  988.             {
  989.                 displayHelp() ;
  990.                 moveArgs( *argc, argv, i, 1 ) ;
  991.                 *argc -= 1 ;
  992.                 i-- ;
  993.             }
  994.             else
  995.             {
  996.                 usage() ;
  997.             }
  998.         }
  999.     }
  1000. }
  1001.  
  1002.  
  1003.  
  1004. /*------------------------------------------------------------------------------
  1005.  * Rearrange argument list.
  1006.  *----------------------------------------------------------------------------*/
  1007. static void
  1008. moveArgs(
  1009.     int    argc,
  1010.     char    **argv,
  1011.     int    start,
  1012.     int    n
  1013.     )
  1014. {
  1015.     int    i ;
  1016.     char    *t ;
  1017.  
  1018.     while( n-- )
  1019.     {
  1020.         t = argv[start] ;
  1021.         for( i = start ; i < argc - 1 ; i++ )
  1022.         {
  1023.             argv[i] = argv[i+1] ;
  1024.         }
  1025.         argv[argc-1] = t ;
  1026.     }
  1027. }
  1028.  
  1029.  
  1030.  
  1031. /*------------------------------------------------------------------------------
  1032.  * End the program and clean up.
  1033.  *----------------------------------------------------------------------------*/
  1034. void
  1035. endProgram(
  1036.     int    status
  1037.     )
  1038. {
  1039.     if( outFd > -1 ) {
  1040.         close( outFd ) ;
  1041.         }
  1042.     if( inFd > -1 ) {
  1043.         close( inFd ) ;
  1044.         }
  1045.  
  1046.     endSound() ;
  1047.  
  1048.     pfExit() ;
  1049.     exit( status ) ;
  1050. }
  1051.  
  1052.  
  1053.  
  1054. /*------------------------------------------------------------------------------
  1055.  * Copy over a player structure.
  1056.  *----------------------------------------------------------------------------*/
  1057. void
  1058. copyPlayer(
  1059.     int    k,
  1060.     Player *psrc
  1061.     )
  1062. {
  1063.     bcopy( psrc, &( player[k] ), sizeof( Player ) ) ;
  1064. }
  1065.  
  1066.  
  1067.  
  1068. /*------------------------------------------------------------------------------
  1069.  * Check for duplicate id's.
  1070.  *----------------------------------------------------------------------------*/
  1071. void
  1072. checkId(
  1073.     int n
  1074.     )
  1075. {
  1076.     struct in_addr    addr ;
  1077.     struct hostent    *hp ;
  1078.  
  1079.     if( !demoMode && player[n].id == player[SELF].id )
  1080.     {
  1081.         addr.s_addr = player[n].id ;
  1082.         hp = gethostbyaddr( &addr, sizeof(addr), AF_INET ) ;
  1083.         fprintf( stderr, "\n%s@%s is using your host id!\n\n",
  1084.             player[n].name, hp ? hp->h_name : inet_ntoa(addr) ) ;
  1085.         endProgram( 1 ) ;
  1086.     }
  1087. }
  1088.  
  1089.  
  1090.  
  1091. /*------------------------------------------------------------------------------
  1092.  * Find a player given his id.
  1093.  *----------------------------------------------------------------------------*/
  1094. int
  1095. findPlayer(
  1096.     long    id
  1097.     )
  1098. {
  1099.     int    i ;
  1100.  
  1101.     for( i = ENEMY ; i < numberPlayers ; i++ )
  1102.     {
  1103.         if( player[i].id == id )
  1104.         {
  1105.             return( i ) ;
  1106.         }
  1107.     }
  1108.  
  1109.     return( 0 ) ;
  1110. }
  1111.  
  1112.  
  1113.  
  1114. /*------------------------------------------------------------------------------
  1115.  * Delete a player.
  1116.  *----------------------------------------------------------------------------*/
  1117. void
  1118. deletePlayer(
  1119.     int    i,
  1120.     char    *verb
  1121.     )
  1122. {
  1123.     int    j ;
  1124.  
  1125.     postNewMessage( "%s %s.", player[i].name, verb ) ;
  1126.  
  1127.     if( networking ) {
  1128.         ngRemoveHostFromCensus( player[i].id ) ;
  1129.         ngDprintf( "%s: %s %s.\n", ngPrintTime(),
  1130.             ngHostNameFromId( player[i].id ), verb ) ;
  1131.         }
  1132.  
  1133.     deleteExplosion( i, mainScene ) ;
  1134.  
  1135.     while( pfGetNumChildren( trikeSwitch[i] ) )
  1136.     {
  1137.         pfRemoveChild( trikeSwitch[i],
  1138.                 pfGetChild( trikeSwitch[i], 0 ) ) ;
  1139.     }
  1140.  
  1141.     pfRemoveChild( vehicleGroup, trike[i] ) ;
  1142.  
  1143.     for( j = i ; j < numberPlayers-1 ; j++ )
  1144.     {
  1145.         copyPlayer( j, &(player[j+1]) ) ;
  1146.         activity[j] = activity[j+1] ;
  1147.         pShield[j] = pShield[j+1] ;
  1148.         trike[j] = trike[j+1] ;
  1149.         trikeSwitch[j] = trikeSwitch[j+1] ;
  1150.         PFCOPY_VEC3( velocity[j], velocity[j+1] ) ;
  1151.         PFCOPY_VEC3( acceleration[j], acceleration[j+1] ) ;
  1152.         pfNodeTravData( trike[j], PFTRAV_ISECT, (void *)j ) ;
  1153.     }
  1154.  
  1155.     numberPlayers-- ;
  1156.     activity[numberPlayers] = 0 ;
  1157.  
  1158.     updatePlayerCounter() ;
  1159. }
  1160.  
  1161.  
  1162.  
  1163. /*------------------------------------------------------------------------------
  1164.  * Reset function.
  1165.  *----------------------------------------------------------------------------*/
  1166. void
  1167. reset(
  1168.     void
  1169.     )
  1170. {
  1171.     selfStatus = OORT_ST_CONFIGURING ;
  1172.     setMainDrawFunction() ;
  1173.  
  1174.     cloakOn = 0 ;
  1175.     selfDestruct = 0 ;
  1176.     latitude = 0.0f ;
  1177.     longitude = 0.0f ;
  1178.     speed = 0.0f ;
  1179.     shields = 1.0f ;
  1180.     power = 1.0f ;
  1181.     laser = 1.0f ;
  1182.     cloak = 1.0f ;
  1183.     laserCharge = 0.25f ;
  1184.     shieldRegenRate = 0.020f ;
  1185.     cloakRegenRate = 0.10f ;
  1186.     laserRegenRate = 1.0f / 3.0f ;
  1187.     pitch = 0.0f ;
  1188.     roll = 0.0f ;
  1189.     player[SELF].status = 0 ;
  1190.     player[SELF].hitById = 0 ;
  1191.     PFSET_VEC3( player[SELF].xyz, 0.0f, (float)(-10.0f * ASTEROID_RADIUS),
  1192.             0.0f ) ;
  1193.     leftMouseHit = 0 ;
  1194.     rightMouseHit = 0 ;
  1195.  
  1196.     radarMaxRange() ;
  1197. }
  1198.  
  1199.  
  1200.  
  1201. /*------------------------------------------------------------------------------
  1202.  * Print out a 4x4 matrix.
  1203.  *----------------------------------------------------------------------------*/
  1204. void
  1205. printMat(
  1206.     char        *label,
  1207.     pfMatrix    m
  1208.     )
  1209. {
  1210.     int    i ;
  1211.  
  1212.     printf( "%s\n", label ) ;
  1213.  
  1214.     for( i = 0 ; i < 4 ; i++ )
  1215.     {
  1216.         printf( "%10.6f %10.6f %10.6f %10.6f\n", m[i][0], m[i][1],
  1217.             m[i][2], m[i][3] ) ;
  1218.     }
  1219. }
  1220.  
  1221.  
  1222.  
  1223. /*------------------------------------------------------------------------------
  1224.  * Determine compass heading.
  1225.  *----------------------------------------------------------------------------*/
  1226. float
  1227. getHeading(
  1228.     void
  1229.     )
  1230. {
  1231.     float        d ;
  1232.     pfVec3        pos ;
  1233.     pfVec3        v ;
  1234.     pfVec3        east ;
  1235.     static pfVec3    north = { 0.0f, 0.0f, 1.0f } ;
  1236.  
  1237.     if( selfStatus == OORT_ST_ON_GROUND )
  1238.     {
  1239.         PFCOPY_VEC3( pos, motion.cg ) ;
  1240.         pos[2] = 0.0f ;
  1241.  
  1242.         if( pfNormalizeVec3( pos ) == 0.0f )
  1243.         {
  1244.             return( 0.0f ) ;
  1245.         }
  1246.  
  1247.         pfCrossVec3( east, north, pos ) ;
  1248.  
  1249.         d = -PFDOT_VEC3( pos, ahead ) ;
  1250.         v[0] = ahead[0] + d * pos[0] ;
  1251.         v[1] = ahead[1] + d * pos[1] ;
  1252.         v[2] = ahead[2] + d * pos[2] ;
  1253.  
  1254.         return( pfArcTan2( PFDOT_VEC3( v, east ),
  1255.                     PFDOT_VEC3( v, north ) ) ) ;
  1256.     }
  1257.     else
  1258.     {
  1259.         return( 0.0f ) ;
  1260.     }
  1261. }
  1262.  
  1263.  
  1264.  
  1265.  
  1266. /*------------------------------------------------------------------------------
  1267.  * Print a label and a vector (debug).
  1268.  *----------------------------------------------------------------------------*/
  1269. void
  1270. printVec3(
  1271.     char    *label,
  1272.     pfVec3    v
  1273.     )
  1274. {
  1275.     printf( "%s: %f %f %f\n", label, v[0], v[1], v[2] ) ;
  1276. }
  1277.  
  1278.  
  1279.  
  1280. /*------------------------------------------------------------------------------
  1281.  * Repaint compass background.
  1282.  *----------------------------------------------------------------------------*/
  1283. static void
  1284. repaintCompass(
  1285.     void
  1286.     )
  1287. {
  1288.     static float    tick[8][2] = {
  1289.                 {  0.0f,  1.0f }, {  0.0f,  0.8f },
  1290.                 {  0.0f, -1.0f }, {  0.0f, -0.8f },
  1291.                 {  1.0f,  0.0f }, {  0.8f,  0.0f },
  1292.                 { -1.0f,  0.0f }, { -0.8f,  0.0f },
  1293.                 } ;
  1294.  
  1295.     viewport( headingVP.left, headingVP.right, headingVP.bottom,
  1296.         headingVP.top ) ;
  1297.     ortho2( -1.0f, 1.0f, -1.0f, 1.0f ) ;
  1298.     cpack( 0x0 ) ;
  1299.     clear() ;
  1300.     cpack( 0x00ffffff ) ;
  1301.     bgnline() ;
  1302.         v2f( tick[0] ) ;
  1303.         v2f( tick[1] ) ;
  1304.     endline() ;
  1305.     bgnline() ;
  1306.         v2f( tick[2] ) ;
  1307.         v2f( tick[3] ) ;
  1308.     endline() ;
  1309.     bgnline() ;
  1310.         v2f( tick[4] ) ;
  1311.         v2f( tick[5] ) ;
  1312.     endline() ;
  1313.     bgnline() ;
  1314.         v2f( tick[6] ) ;
  1315.         v2f( tick[7] ) ;
  1316.     endline() ;
  1317. }
  1318.  
  1319.  
  1320.  
  1321. /*------------------------------------------------------------------------------
  1322.  * Initialize enemy structures.
  1323.  *----------------------------------------------------------------------------*/
  1324. static void
  1325. initEnemies(
  1326.     void
  1327.     )
  1328. {
  1329.     int    i ;
  1330.  
  1331.     for( i = SELF ; i < MAXPLAYERS ; i++ )
  1332.     {
  1333.         playerMatrix[i][0][3] = 0.0f ;
  1334.         playerMatrix[i][1][3] = 0.0f ;
  1335.         playerMatrix[i][2][3] = 0.0f ;
  1336.         playerMatrix[i][3][3] = 1.0f ;
  1337.     }
  1338. }
  1339.  
  1340.  
  1341.  
  1342. /*------------------------------------------------------------------------------
  1343.  * Transform a vector by a 4x4 matrix (v = v * m).
  1344.  *----------------------------------------------------------------------------*/
  1345. static void
  1346. vecMultMatInPlace(
  1347.     pfVec4        v,
  1348.     pfMatrix    m
  1349.     )
  1350. {
  1351.     pfVec4    a ;
  1352.     int    i ;
  1353.     int    j ;
  1354.  
  1355.     a[0] = v[0] ;
  1356.     a[1] = v[1] ;
  1357.     a[2] = v[2] ;
  1358.     a[3] = v[3] ;
  1359.  
  1360.     for( i = 0 ; i < 4 ; i++ )
  1361.     {
  1362.         v[i] = 0.0 ;
  1363.         for( j = 0 ; j < 4 ; j++ )
  1364.         {
  1365.             v[i] += a[j] * m[j][i] ;
  1366.         }
  1367.     }
  1368. }
  1369.  
  1370.  
  1371.  
  1372. /*------------------------------------------------------------------------------
  1373.  * Add a player.
  1374.  *----------------------------------------------------------------------------*/
  1375. int
  1376. addPlayer(
  1377.     Player    *input
  1378.     )
  1379. {
  1380.     int    number ;
  1381.  
  1382.     if( numberPlayers <= MAXPLAYERS )
  1383.     {
  1384.         number = numberPlayers ;
  1385.         numberPlayers++ ;
  1386.     }
  1387.     else
  1388.     {
  1389.         fprintf( stderr, "%s: maximum number (%d) of players "
  1390.             "exceeded.\n", basename, MAXPLAYERS ) ;
  1391.         endProgram( 0 ) ;
  1392.     }
  1393.  
  1394.     copyPlayer( number, input ) ;
  1395.  
  1396.     trike[number] = pfNewDCS() ;
  1397.     pfAddChild( vehicleGroup, trike[number] ) ;
  1398.     trikeSwitch[number] = pfNewGroup() ;
  1399.     pfAddChild( trike[number], trikeSwitch[number] ) ;
  1400.  
  1401.     pfNodeTravMask( trike[number], PFTRAV_ISECT, LASER_MASK | VEHICLE_MASK,
  1402.             PFTRAV_SELF | PFTRAV_IS_CACHE, PF_SET ) ;
  1403.     pfAddChild( trikeSwitch[number],
  1404.         pfClone( vehicle[player[number].team], 0 ) ) ;
  1405.     if( ( pShield[number] = (pfGroup *)pfClone( shield, 0 ) ) == NULL )
  1406.     {
  1407.         fprintf( stderr, "%s: error cloning shield node\n", basename ) ;
  1408.         endProgram( 1 ) ;
  1409.     }
  1410.     pfAddChild( trikeSwitch[number], pShield[number] ) ;
  1411.     pfNodeTravMask( pShield[number], PFTRAV_DRAW, 0, PFTRAV_SELF, PF_SET ) ;
  1412.  
  1413.     pfNodeBSphere( trikeSwitch[number], vehicleBoundingSphere,
  1414.             PFN_BMODE_STATIC ) ;
  1415.  
  1416.     pfNodeTravFuncs( trikeSwitch[number], PFTRAV_ISECT,
  1417.             fireLaserPreTravCB, fireLaserPostTravCB ) ;
  1418.     pfNodeTravData( trikeSwitch[number], PFTRAV_ISECT, (void *)number ) ;
  1419.  
  1420.     addExplosion( number, mainScene ) ;
  1421.  
  1422.     PFSET_VEC3( velocity[number], 0.0f, 0.0f, 0.0f ) ;
  1423.     PFSET_VEC3( acceleration[number], 0.0f, 0.0f, 0.0f ) ;
  1424.  
  1425.     updatePlayerCounter() ;
  1426.  
  1427.     return( number ) ;
  1428. }
  1429.  
  1430.  
  1431.  
  1432. /*------------------------------------------------------------------------------
  1433.  * Pick the landing site with the mouse.
  1434.  *----------------------------------------------------------------------------*/
  1435. static int
  1436. pickLandingSite(
  1437.     pfVec3    landingSite
  1438.     )
  1439. {
  1440.     int    st = 0 ;
  1441.     long    flags ;
  1442.     pfHit    **hits[1] ;
  1443.  
  1444.     doPick( (pfNode *)terrain, PFTRAV_IS_PRIM | PFPK_M_NEAREST,
  1445.         GROUND_MASK, hits ) ;
  1446.     pfQueryHit( hits[0][0], PFQHIT_FLAGS, &flags ) ;
  1447.  
  1448.     if( flags & PFHIT_POINT )
  1449.     {
  1450.         pfQueryHit( hits[0][0], PFQHIT_POINT, landingSite ) ;
  1451.         st = 1 ;
  1452.     }
  1453.     else
  1454.     {
  1455.         st = 0 ;
  1456.     }
  1457.  
  1458.     return( st ) ;
  1459. }
  1460.  
  1461.  
  1462.  
  1463. /*------------------------------------------------------------------------------
  1464.  * Fire laser.
  1465.  *----------------------------------------------------------------------------*/
  1466. static void
  1467. fireLaser(
  1468.     void
  1469.     )
  1470. {
  1471.     int    i ;
  1472.     float    ls ;
  1473.     float    d ;
  1474.     pfHit    **hits[1] ;
  1475.     long    flags ;
  1476.     pfNode    *node ;
  1477.  
  1478.     sfx( SFX_FIRE ) ;
  1479.  
  1480.     if( laser > laserCharge )
  1481.     {
  1482.         laser -= laserCharge ;
  1483.         ls = 1.0f ;
  1484.     }
  1485.     else
  1486.     {
  1487.         ls = laser / laserCharge ;
  1488.         laser = 0.0f ;
  1489.     }
  1490.  
  1491.     trikeHit = 0 ;
  1492.     checkTrike = 0 ;
  1493.     doPick( (pfNode *)terrainAndVehicles,
  1494.         PFTRAV_IS_PRIM | PFTRAV_IS_NO_PART, LASER_MASK, hits ) ;
  1495.     pfQueryHit( hits[0][0], PFQHIT_FLAGS, &flags ) ;
  1496.  
  1497.     if( ( flags & PFQHIT_NODE ) != 0 && trikeHit > 0 )
  1498.     {
  1499.  
  1500.         pfQueryHit( hits[0][0], PFQHIT_NODE, (float *)&node ) ;
  1501.         if( pfGetNodeTravMask( node, PFTRAV_ISECT ) & VEHICLE_MASK )
  1502.         {
  1503.             /*
  1504.              * Decrease laser effectiveness with distance.
  1505.              */
  1506.             d = pfSqrt( pfDistancePt3( player[SELF].xyz,
  1507.                     player[trikeHit].xyz ) ) ;
  1508.             ls -= .050 * d ;
  1509.             if( ls < 0.0f )
  1510.             {
  1511.                 ls = 0.0f ;
  1512.             }
  1513.  
  1514.             if( !networking )
  1515.             {
  1516.                 pfNodeTravMask( pShield[trikeHit], PFTRAV_DRAW,
  1517.                     0xffffffff, PFTRAV_SELF, PF_SET ) ;
  1518.                 player[trikeHit].status |=
  1519.                         OORT_ST_SHIELDS ;
  1520.                 player[SELF].laserStrength = 1 ;
  1521.             }
  1522.             else
  1523.             {
  1524.                 player[SELF].hitId =
  1525.                         player[trikeHit].id ;
  1526.                 player[SELF].laserStrength =
  1527.                         ls * 255 * laserFactor ;
  1528.             }
  1529.         }
  1530.     }
  1531.     else if( !networking )
  1532.     {
  1533.         player[SELF].laserStrength = 1 ;
  1534.     }
  1535. }
  1536.  
  1537.  
  1538.  
  1539. /*------------------------------------------------------------------------------
  1540.  * Pick a player to determine his name.
  1541.  *----------------------------------------------------------------------------*/
  1542. static void
  1543. pickPlayer(
  1544.     void
  1545.     )
  1546. {
  1547.     long    flags ;
  1548.     pfHit    **hits[1] ;
  1549.  
  1550.     trikeHit = 0 ;
  1551.     checkTrike = 0 ;
  1552.     doPick( (pfNode *)terrainAndVehicles,
  1553.         PFTRAV_IS_PRIM | PFTRAV_IS_NO_PART, LASER_MASK, hits ) ;
  1554.     pfQueryHit( hits[0][0], PFQHIT_FLAGS, &flags ) ;
  1555.  
  1556.     if( ( flags & PFQHIT_NODE ) != 0 && trikeHit > 0 )
  1557.     {
  1558.         postNewMessage( "Looking at %s.", player[trikeHit].name ) ;
  1559.         sfx( SFX_OK ) ;
  1560.     }
  1561. }
  1562.  
  1563.  
  1564.  
  1565. /*------------------------------------------------------------------------------
  1566.  * Pre-traversal callback function when firing laser.
  1567.  *----------------------------------------------------------------------------*/
  1568. static long
  1569. fireLaserPreTravCB(
  1570.     pfTraverser    *trav,
  1571.     void        *data
  1572.     )
  1573. {
  1574.     checkTrike = (int)data ;
  1575.     return( PFTRAV_CONT ) ;
  1576. }
  1577.  
  1578.  
  1579.  
  1580. /*------------------------------------------------------------------------------
  1581.  * Post-traversal callback function when firing laser.
  1582.  *----------------------------------------------------------------------------*/
  1583. static long
  1584. fireLaserPostTravCB(
  1585.     pfTraverser    *trav,
  1586.     void        *data
  1587.     )
  1588. {
  1589.     pfSphere    sphere ;
  1590.     pfMatrix    mat ;
  1591.  
  1592.     checkTrike = 0 ;
  1593.  
  1594.     return( PFTRAV_CONT | PFTRAV_IS_CLIP_END ) ;
  1595. }
  1596.  
  1597.  
  1598.  
  1599. /*------------------------------------------------------------------------------
  1600.  * Load customizations from ~/.oortrc file.
  1601.  *----------------------------------------------------------------------------*/
  1602. static void
  1603. loadCustom(
  1604.     void
  1605.     )
  1606. {
  1607.     int        i ;
  1608.     int        err ;
  1609.     FILE        *f ;
  1610.     char        *s ;
  1611.     char        line[256] ;
  1612.     char        path[MAXPATHLEN] ;
  1613.     static char    *name = ".oortrc" ;
  1614.  
  1615.     /*
  1616.      * Try in current directory first.
  1617.      */
  1618.     sprintf( path, "./%s", name ) ;
  1619.     if( ( f = fopen( path, "r" ) ) == NULL )
  1620.     {
  1621.         /*
  1622.          * Try in home directory next.
  1623.          */
  1624.         if( getenv( "HOME" ) )
  1625.         {
  1626.             sprintf( path, "%s/%s", getenv( "HOME" ), name ) ;
  1627.             if( ( f = fopen( path, "r" ) ) == NULL )
  1628.             {
  1629.                 /*
  1630.                  * Couldn't find it.
  1631.                  */
  1632.                 noConfigFile( path ) ;
  1633.                 return ;
  1634.             }
  1635.         }
  1636.     }
  1637.  
  1638.     while( fgets( line, 256, f ) != NULL )
  1639.     {
  1640.         /*
  1641.          * Skip comment lines.
  1642.          */
  1643.         if( line[0] == '#' )
  1644.         {
  1645.             continue ;
  1646.         }
  1647.  
  1648.         if( strncmp( line, "terrainColor:", 13 ) == 0 )
  1649.         {
  1650.             err = readColor( line+13, groundColor ) ;
  1651.         }
  1652.         else if( strncmp( line, "teamColorA:", 11 ) == 0 )
  1653.         {
  1654.             err = readColor( line+11, teamColor[0] ) ;
  1655.         }
  1656.         else if( strncmp( line, "teamColorB:", 11 ) == 0 )
  1657.         {
  1658.             err = readColor( line+11, teamColor[1] ) ;
  1659.         }
  1660.         else if( strncmp( line, "teamColorC:", 11 ) == 0 )
  1661.         {
  1662.             err = readColor( line+11, teamColor[2] ) ;
  1663.         }
  1664.         else if( strncmp( line, "teamColorD:", 11 ) == 0 )
  1665.         {
  1666.             err = readColor( line+11, teamColor[3] ) ;
  1667.         }
  1668.         else if( strncmp( line, "name:", 5 ) == 0 )
  1669.         {
  1670.             i = 5 ;
  1671.             while( isspace( line[i] ) )
  1672.             {
  1673.                 i++ ;
  1674.             }
  1675.             strncpy( playerName, line+i, NAMELEN ) ;
  1676.             playerName[NAMELEN-1] = '\0' ;
  1677.             if( strlen( playerName ) == 0 )
  1678.             {
  1679.                 err = 1 ;
  1680.             }
  1681.             else
  1682.             {
  1683.                 if( ( s = strchr( playerName, '\n' ) ) != NULL )
  1684.                 {
  1685.                     *s = '\0' ;
  1686.                 }
  1687.             }
  1688.         }
  1689.         else if( strncmp( line, "volume:", 7 ) == 0 )
  1690.         {
  1691.             if( sscanf( line+7, "%d", &initialVol ) != 1 ||
  1692.                 initialVol < -1 || initialVol > 10 )
  1693.             {
  1694.                 err = 1 ;
  1695.             }
  1696.         }
  1697.         else if( strncmp( line, "TTL:", 4 ) == 0 )
  1698.         {
  1699.             if( sscanf( line+4, "%d", &timeToLive ) != 1 ||
  1700.                 timeToLive < NG_MIN_TTL ||
  1701.                 timeToLive > NG_MAX_TTL )
  1702.             {
  1703.                 err = 1 ;
  1704.                 timeToLive = NG_DEFAULT_TTL ;
  1705.             }
  1706.         }
  1707.         else if( strncmp( line, "textLines:", 10 ) == 0 )
  1708.         {
  1709.             if( sscanf( line+10, "%d", &nTextLines ) != 1 ||
  1710.                 nTextLines < 1 )
  1711.             {
  1712.                 err = 1 ;
  1713.             }
  1714.             else if( nTextLines > MAX_TEXT_LINES )
  1715.             {
  1716.                 nTextLines = MAX_TEXT_LINES ;
  1717.             }
  1718.         }
  1719.         else if( strncmp( line, "configuration:", 14 ) == 0 )
  1720.         {
  1721.             err = setDefaultConfig( line+14 ) ;
  1722.         }
  1723.         else
  1724.         {
  1725.             err = 0 ;
  1726.             fprintf( stderr, "%s: unknown entry in `%s'\n",
  1727.                 basename, path ) ;
  1728.             fprintf( stderr, " -->%s", line ) ;
  1729.         }
  1730.  
  1731.         if( err )
  1732.         {
  1733.             fprintf( stderr, "%s: error in `%s'\n",
  1734.                 basename, path ) ;
  1735.             fprintf( stderr, " -->%s", line ) ;
  1736.         }
  1737.     }
  1738.  
  1739.     fclose( f ) ;
  1740. }
  1741.  
  1742.  
  1743.  
  1744. /*------------------------------------------------------------------------------
  1745.  * Read 3 floats from a string and store in a vector.
  1746.  *----------------------------------------------------------------------------*/
  1747. static int
  1748. readColor(
  1749.     char    *s,
  1750.     pfVec3    v
  1751.     )
  1752. {
  1753.     int    err ;
  1754.     pfVec3    t ;
  1755.  
  1756.     if( sscanf( s, "%f %f %f", t+0, t+1, t+2 ) != 3 ||
  1757.         t[0] < 0.0f || 1.0f < t[0] ||
  1758.         t[1] < 0.0f || 1.0f < t[1] ||
  1759.         t[2] < 0.0f || 1.0f < t[2] )
  1760.     {
  1761.         err = 1 ;
  1762.     }
  1763.     else
  1764.     {
  1765.         PFCOPY_VEC3( v, t ) ;
  1766.         err = 0 ;
  1767.     }
  1768.  
  1769.     return( err ) ;
  1770. }
  1771.  
  1772.  
  1773.  
  1774. /*------------------------------------------------------------------------------
  1775.  * Initialize a bunch o' stuff.
  1776.  *----------------------------------------------------------------------------*/
  1777. static void
  1778. initStuff(
  1779.     void
  1780.     )
  1781. {
  1782.     pfPipe    *p ;
  1783.  
  1784.     p = pfGetPipe(0);
  1785.     pfInitPipe( p, openPipe ) ;
  1786.  
  1787.     setupChannels( p ) ;
  1788.  
  1789.     starObj = makeBackground() ;
  1790.  
  1791.     makeRadarBackground( 9, 12 ) ;
  1792.  
  1793.     helpObj = makeHelpOverlay() ;
  1794.  
  1795.     initDashboard() ;
  1796.  
  1797.     defpattern( HALFTONE_PATTERN, 16, halftone ) ;
  1798.     defpattern( STATIC_PATTERN_0, 16, staticPattern[0] ) ;
  1799.     defpattern( STATIC_PATTERN_1, 16, staticPattern[1] ) ;
  1800.     defpattern( STATIC_PATTERN_2, 16, staticPattern[2] ) ;
  1801.  
  1802.     pfChanScene( mainChan, mainScene ) ;
  1803.  
  1804.     initEnemies() ;
  1805.  
  1806.     initConfigureScreen() ;
  1807.  
  1808.     initCom() ;
  1809.  
  1810.     if( initialVol > -1 )
  1811.     {
  1812.         initSound() ;
  1813.         if( initialVol < 11 )
  1814.         {
  1815.             setVolume( initialVol ) ;
  1816.         }
  1817.     }
  1818.  
  1819.     pfDisable( PFEN_FOG ) ;
  1820.     pfDisable( PFEN_TEXTURE ) ;
  1821. }
  1822.  
  1823.  
  1824.  
  1825. /*------------------------------------------------------------------------------
  1826.  * Distribute power.
  1827.  *----------------------------------------------------------------------------*/
  1828. static void
  1829. distributePower(
  1830.     void
  1831.     )
  1832. {
  1833.     float    powerNeeded = 0.0f ;
  1834.     float    powerAvail ;
  1835.     float    shieldPowerNeeded ;
  1836.     float    laserPowerNeeded ;
  1837.     float    cloakPowerNeeded ;
  1838.  
  1839.     /*
  1840.      * Route power to engine.
  1841.      */
  1842.     power -= speedPowerReq() ;
  1843.     if( power < 0.0f )
  1844.         power = 0.0f ;
  1845.     powerAvail = eTime * 0.15f * solarRate ;
  1846.     if( powerAvail > power )
  1847.         powerAvail = power ;
  1848.  
  1849.     /*
  1850.      * Next, shields get as much power as needed.
  1851.      */
  1852.     shieldPowerNeeded = eTime * shieldRegenRate ;
  1853.     if( shieldPowerNeeded > 1.0f - shields )
  1854.     {
  1855.         shieldPowerNeeded = 1.0f - shields ;
  1856.     }
  1857.     if( powerAvail > shieldPowerNeeded )
  1858.     {
  1859.         shields += shieldPowerNeeded ;
  1860.         powerAvail -= shieldPowerNeeded ;
  1861.         power -= shieldPowerNeeded ;
  1862.     }
  1863.     else
  1864.     {
  1865.         shields += powerAvail ;
  1866.         power -= powerAvail ;
  1867.         powerAvail = 0.0f ;
  1868.     }
  1869.  
  1870.     /*
  1871.      * Next, lasers get as much power as needed.
  1872.      */
  1873.     laserPowerNeeded = eTime * laserRegenRate ;
  1874.     if( laserPowerNeeded > 1.0f - laser )
  1875.     {
  1876.         laserPowerNeeded = 1.0f - laser ;
  1877.     }
  1878.     if( powerAvail > laserPowerNeeded )
  1879.     {
  1880.         laser += laserPowerNeeded ;
  1881.         powerAvail -= laserPowerNeeded ;
  1882.         power -= laserPowerNeeded ;
  1883.     }
  1884.     else
  1885.     {
  1886.         laser += powerAvail ;
  1887.         power -= powerAvail ;
  1888.         powerAvail = 0.0f ;
  1889.     }
  1890.  
  1891.     /*
  1892.      * Drain power due to cloaking.
  1893.      */
  1894.     if( cloakOn )
  1895.     {
  1896.         cloak -= eTime * cloakRate ;
  1897.         if( cloak < 0.0f )
  1898.         {
  1899.             cloak = 0.0f ;
  1900.             cloakOn = 0 ;
  1901.             player[SELF].status &= ~OORT_ST_CLOAK ;
  1902.         }
  1903.     }
  1904.     else
  1905.     {
  1906.         /*
  1907.          * Whatever's left goes toward regenerating the cloaking device.
  1908.          */
  1909.         cloakPowerNeeded = eTime * cloakRegenRate ;
  1910.         if( cloakPowerNeeded > 1.0f - cloak )
  1911.         {
  1912.             cloakPowerNeeded = 1.0f - cloak ;
  1913.         }
  1914.         if( powerAvail > cloakPowerNeeded )
  1915.         {
  1916.             cloak += cloakPowerNeeded ;
  1917.             powerAvail -= cloakPowerNeeded ;
  1918.             power -= cloakPowerNeeded ;
  1919.         }
  1920.         else
  1921.         {
  1922.             cloak += powerAvail ;
  1923.             power -= powerAvail ;
  1924.             powerAvail = 0.0f ;
  1925.         }
  1926.     }
  1927.  
  1928.     /*
  1929.      * Regenerate power based on position.  Take dot product of up
  1930.      * vector with sun vector (0,-1,0).
  1931.      */
  1932.     if( power < 1.0f )
  1933.     {
  1934.         if( up[1] < 0.0f )
  1935.         {
  1936.             power -= eTime * solarRate * up[1] ;
  1937.         }
  1938.         /*
  1939.          * Add in effect of "small nuclear power source".
  1940.          */
  1941.         power += eTime * 0.05f ;
  1942.         if( power > 1.0f )
  1943.         {
  1944.             power = 1.0f ;
  1945.         }
  1946.     }
  1947.  
  1948. }
  1949.  
  1950.  
  1951.  
  1952. /*------------------------------------------------------------------------------
  1953.  * Calculate the power required for the current speed.
  1954.  *----------------------------------------------------------------------------*/
  1955. float
  1956. speedPowerReq(
  1957.     void
  1958.     )
  1959. {
  1960.     float    s ;
  1961.  
  1962.     if( speed > 0.0f )
  1963.     {
  1964.         s = speed ;
  1965.     }
  1966.     else
  1967.     {
  1968.         s = -speed ;
  1969.     }
  1970.  
  1971.     s /= topSpeed ;
  1972.  
  1973.     return( eTime * s * s * engineRate ) ;
  1974. }
  1975.  
  1976.  
  1977.  
  1978. /*------------------------------------------------------------------------------
  1979.  * Front end to malloc routine that checks for valid allocation of memory.
  1980.  *----------------------------------------------------------------------------*/
  1981. void *
  1982. myMalloc(
  1983.     size_t    nbytes
  1984.     )
  1985. {
  1986.     void    *p ;
  1987.  
  1988.     p = pfMalloc( nbytes, pfGetSharedArena() ) ;
  1989.  
  1990.     if( p == NULL )
  1991.     {
  1992.         fprintf( stderr, "out of memory\n" ) ;
  1993.     }
  1994.     return( p ) ;
  1995. }
  1996.  
  1997.  
  1998.  
  1999. /*------------------------------------------------------------------------------
  2000.  * Post process players.
  2001.  *----------------------------------------------------------------------------*/
  2002. static void
  2003. postProcessPlayers(
  2004.     void
  2005.     )
  2006. {
  2007.     int    i ;
  2008.  
  2009.     for( i = ENEMY ; i < numberPlayers ; i++ )
  2010.     {
  2011.         pfNodeTravMask( pShield[i], PFTRAV_DRAW, 0, PFTRAV_SELF,
  2012.                 PF_SET ) ;
  2013.     }
  2014. }
  2015.  
  2016.  
  2017.  
  2018. /*------------------------------------------------------------------------------
  2019.  * Post process players in demo mode.
  2020.  *----------------------------------------------------------------------------*/
  2021. static void
  2022. demoPostProcessPlayers(
  2023.     void
  2024.     )
  2025. {
  2026.     postProcessPlayers() ;
  2027.  
  2028.     if( newSelfStatus != selfStatus )
  2029.     {
  2030.         selfStatus = newSelfStatus ;
  2031.  
  2032.         switch( selfStatus )
  2033.         {
  2034.             case OORT_ST_IN_ORBIT :
  2035.                 shields = 1.0f ;
  2036.                 power = 1.0f ;
  2037.                 break ;
  2038.  
  2039.             case OORT_ST_EXIT :
  2040.                 selfStatus = OORT_ST_CONFIGURING ;
  2041.                 shields = 1.0f ;
  2042.                 power = 1.0f ;
  2043.                 break ;
  2044.         }
  2045.  
  2046.         setMainDrawFunction() ;
  2047.     }
  2048. }
  2049.  
  2050.  
  2051.  
  2052. /*------------------------------------------------------------------------------
  2053.  * Blow self up.
  2054.  *----------------------------------------------------------------------------*/
  2055. void
  2056. blowUpSelf(
  2057.     int    hitId
  2058.     )
  2059. {
  2060.     shields = 0.0f ;
  2061.     speed = 0.0f ;
  2062.     power = 0.0f ;
  2063.     player[SELF].score -= 1 ;
  2064.     addLife() ;
  2065.     player[SELF].hitById = hitId ;
  2066.     selfStatus = OORT_ST_DEAD ;
  2067.     player[SELF].status &= ~( OORT_ST_SHIELDS | OORT_ST_IDLE_HIT ) ;
  2068.     player[SELF].status |= OORT_ST_EXPLODING ;
  2069.     deadTime[SELF] = gameTime ;
  2070.     sfx( SFX_STATIC ) ;
  2071.     setMainDrawFunction() ;
  2072. }
  2073.  
  2074.  
  2075.  
  2076. /*------------------------------------------------------------------------------
  2077.  * Toggle cloaking on and off.
  2078.  *----------------------------------------------------------------------------*/
  2079. void
  2080. toggleCloaking(
  2081.     void
  2082.     )
  2083. {
  2084.     if( cloakOn )
  2085.     {
  2086.         if( cloak > 0.0f )
  2087.         {
  2088.             player[SELF].status |= OORT_ST_CLOAK ;
  2089.         }
  2090.         else
  2091.         {
  2092.             cloakOn = 0 ;
  2093.         }
  2094.     }
  2095.     else
  2096.     {
  2097.         player[SELF].status &= ~OORT_ST_CLOAK ;
  2098.     }
  2099. }
  2100.  
  2101.  
  2102.  
  2103. /*------------------------------------------------------------------------------
  2104.  * Set the main channel draw callback function.
  2105.  *----------------------------------------------------------------------------*/
  2106. void
  2107. setMainDrawFunction(
  2108.     void
  2109.     )
  2110. {
  2111.     if( selfStatus == OORT_ST_CONFIGURING )
  2112.     {
  2113.         pfChanDrawFunc( mainChan, drawConfigureScreen ) ;
  2114.     }
  2115.     else if( selfStatus == OORT_ST_DEAD )
  2116.     {
  2117.         pfChanDrawFunc( mainChan, drawStaticScreen ) ;
  2118.     }
  2119.     else
  2120.     {
  2121.         pfChanDrawFunc( mainChan, drawMainChannel ) ;
  2122.     }
  2123. }
  2124.  
  2125.  
  2126.  
  2127. /*------------------------------------------------------------------------------
  2128.  * Define and set the cursor.
  2129.  *----------------------------------------------------------------------------*/
  2130. static void
  2131. initCursor(
  2132.     void
  2133.     )
  2134. {
  2135.     if( getgdesc( GD_BITS_CURSOR ) > 1 )
  2136.     {
  2137.         curstype( C16X2 ) ;
  2138.         defcursor( 1, cursorBitMap2 ) ;
  2139.         drawmode( CURSORDRAW ) ;
  2140.         mapcolor( 1, 255, 255,   0 ) ;
  2141.         drawmode( NORMALDRAW ) ;
  2142.     }
  2143.     else
  2144.     {
  2145.         curstype( C16X1 ) ;
  2146.         defcursor( 1, cursorBitMap1 ) ;
  2147.         drawmode( CURSORDRAW ) ;
  2148.         mapcolor( 1, 255, 255,   0 ) ;
  2149.         mapcolor( 2,   0,   0,   0 ) ;
  2150.         mapcolor( 3,   0,   0,   0 ) ;
  2151.         drawmode( NORMALDRAW ) ;
  2152.     }
  2153.     curorigin( 1, 8, 8 ) ;
  2154.     setcursor( 1, 0, 0 ) ;
  2155.  
  2156. }
  2157.  
  2158.  
  2159.  
  2160. /*------------------------------------------------------------------------------
  2161.  * Take shield damage.
  2162.  *----------------------------------------------------------------------------*/
  2163. void
  2164. shieldDamage(
  2165.     float    strength,
  2166.     int    id
  2167.     )
  2168. {
  2169.     int    n ;
  2170.  
  2171.     if( selfStatus == OORT_ST_ON_GROUND )
  2172.     {
  2173.         sfx( SFX_HIT ) ;
  2174.  
  2175.         shields -= 0.50 * strength / shieldFactor ;
  2176.         if( shields < 0.0f )
  2177.         {
  2178.             blowUpSelf( id ) ;
  2179.             if( id != 0 )
  2180.             {
  2181.                 n = findPlayer( id ) ;
  2182.                 postNewMessage( "Killed by %s.",
  2183.                         player[n].name ) ;
  2184.             }
  2185.             else
  2186.             {
  2187.                 postNewMessage( "Killed by orbital fortress." );
  2188.             }
  2189.         }
  2190.         else
  2191.         {
  2192.             player[SELF].status |= OORT_ST_SHIELDS ;
  2193.             if( id == 0 )
  2194.             {
  2195.                 postNewMessage( "Orbital fortress has locked "
  2196.                         "on." ) ;
  2197.             }
  2198.         }
  2199.     }
  2200. }
  2201.  
  2202.  
  2203.  
  2204. /*------------------------------------------------------------------------------
  2205.  * Find a file in the default directory or according to environment variables.
  2206.  *----------------------------------------------------------------------------*/
  2207. char *
  2208. findFile(
  2209.     char    *file
  2210.     )
  2211. {
  2212.     char    *dir ;
  2213.     char    *path ;
  2214.  
  2215.     if( ( dir = getenv( "OORT_DIR" ) ) == NULL )
  2216.     {
  2217.         dir = DATA_DIR ;
  2218.     }
  2219.     path = malloc( strlen( dir ) + strlen( file ) + 2 ) ;
  2220.  
  2221.     sprintf( path, "%s/%s", dir, file ) ;
  2222.  
  2223.     return( path ) ;
  2224. }
  2225.  
  2226.  
  2227.  
  2228. /*------------------------------------------------------------------------------
  2229.  * The main loop.
  2230.  *----------------------------------------------------------------------------*/
  2231. static void
  2232. mainLoop(
  2233.     void
  2234.     )
  2235. {
  2236.     float        lastTime ;
  2237.     static float    alarmTime = 0.0f ;
  2238.  
  2239.     while( stayInProgram )
  2240.     {
  2241.         while( selfStatus == OORT_ST_ON_GROUND )
  2242.         {
  2243.             /* Go to sleep till next frame time */
  2244.             pfSync() ;
  2245.  
  2246.             gameTime = pfGetTime() ;
  2247.             eTime = gameTime - lastTime ;
  2248.             lastTime = gameTime ;
  2249.  
  2250.             if( shields < 0.25f && gameTime - alarmTime > 2.0f )
  2251.             {
  2252.                 alarmTime = gameTime ;
  2253.                 sfx( SFX_ALARM ) ;
  2254.             }
  2255.  
  2256.             moveSelf( terrain ) ;
  2257.  
  2258.             if( gameTime - idleStartTime > 5.0f )
  2259.             {
  2260.                 player[SELF].status |= OORT_ST_IDLE_HIT ;
  2261.                 idleStartTime += 2.0f ;
  2262.                 shieldDamage( 0.50f, 0 ) ;
  2263.             }
  2264.             else
  2265.             {
  2266.                 player[SELF].status &= ~OORT_ST_IDLE_HIT ;
  2267.             }
  2268.  
  2269.             getLatLong() ;
  2270.  
  2271.             writePackets() ;
  2272.             player[SELF].status &= ~OORT_ST_SHIELDS ;
  2273.             readPackets() ;
  2274.  
  2275.             updateViewGround() ;
  2276.  
  2277.             distributePower() ;
  2278.  
  2279.             pfFrame();
  2280.  
  2281.             postProcessPlayers() ;
  2282.  
  2283.             if( leftMouseHit )
  2284.             {
  2285.                 fireLaser() ;
  2286.                 leftMouseHit = 0 ;
  2287.             }
  2288.  
  2289.             if( rightMouseHit )
  2290.             {
  2291.                 pickPlayer() ;
  2292.                 rightMouseHit = 0 ;
  2293.             }
  2294.  
  2295.             if( selfDestruct )
  2296.             {
  2297.                 if( gameTime - selfDestructTime >= 10.0f )
  2298.                 {
  2299.                     blowUpSelf( 0 ) ;
  2300.                 }
  2301.                 else if( gameTime - selfDestructAlarmTime >
  2302.                     2.0f )
  2303.                 {
  2304.                     selfDestructAlarmTime = gameTime ;
  2305.                     sfx( SFX_ALARM ) ;
  2306.                 }
  2307.             }
  2308.         }
  2309.  
  2310.         while( selfStatus == OORT_ST_IN_ORBIT )
  2311.         {
  2312.             /* Go to sleep till next frame time */
  2313.             pfSync() ;
  2314.  
  2315.             gameTime = pfGetTime() ;
  2316.             eTime = gameTime - lastTime ;
  2317.             lastTime = gameTime ;
  2318.  
  2319.             writePackets() ;
  2320.             player[SELF].status &= ~OORT_ST_SHIELDS ;
  2321.             readPackets() ;
  2322.  
  2323.             updateViewInOrbit() ;
  2324.  
  2325.             pfFrame();
  2326.  
  2327.             postProcessPlayers() ;
  2328.         }
  2329.  
  2330.         while( selfStatus == OORT_ST_DEAD )
  2331.         {
  2332.             /* Go to sleep till next frame time */
  2333.             pfSync() ;
  2334.  
  2335.             gameTime = pfGetTime() ;
  2336.             eTime = gameTime - lastTime ;
  2337.             lastTime = gameTime ;
  2338.  
  2339.             writePackets() ;
  2340.             player[SELF].status &= ~OORT_ST_SHIELDS ;
  2341.             readPackets() ;
  2342.  
  2343.             updateViewGround() ;
  2344.  
  2345.             pfFrame();
  2346.  
  2347.             postProcessPlayers() ;
  2348.  
  2349.             if( gameTime - deadTime[SELF] > 5.0f )
  2350.             {
  2351.                 reset() ;
  2352.             }
  2353.             else
  2354.             {
  2355.                 power = ( gameTime - deadTime[SELF] ) / 5.0f ;
  2356.             }
  2357.         }
  2358.  
  2359.         while( selfStatus == OORT_ST_CONFIGURING )
  2360.         {
  2361.             /* Go to sleep till next frame time */
  2362.             pfSync() ;
  2363.  
  2364.             gameTime = pfGetTime() ;
  2365.             eTime = gameTime - lastTime ;
  2366.             lastTime = gameTime ;
  2367.  
  2368.             writePackets() ;
  2369.             player[SELF].status &= ~OORT_ST_SHIELDS ;
  2370.             readPackets() ;
  2371.  
  2372.             pfFrame();
  2373.  
  2374.             postProcessPlayers() ;
  2375.         }
  2376.     }
  2377. }
  2378.  
  2379.  
  2380.  
  2381. /*------------------------------------------------------------------------------
  2382.  * Channel draw callback - draw dead screen.
  2383.  *----------------------------------------------------------------------------*/
  2384. static void
  2385. drawStaticScreen(
  2386.     pfChannel    *channel,
  2387.     void        *data
  2388.     )
  2389. {
  2390.     float        x ;
  2391.     float        y ;
  2392.     static char    *msg = "Signal lost." ;
  2393.  
  2394.     /*
  2395.      * Get input.
  2396.      */
  2397.     grabInput() ;
  2398.  
  2399.     pfPushState() ;
  2400.     pfBasicState() ;
  2401.  
  2402.     zfunction( ZF_ALWAYS ) ;
  2403.         zwritemask( 0x0 ) ;
  2404.     if( gameTime - deadTime[SELF] > 0.5f )
  2405.     {
  2406.         if( mainVP.right - mainVP.left > mainVP.top - mainVP.bottom )
  2407.         {
  2408.             y = mainVP.top - mainVP.bottom ;
  2409.             x = (float)( mainVP.right - mainVP.left ) / y ;
  2410.             y = 1.0f ;
  2411.         }
  2412.         else
  2413.         {
  2414.             x = mainVP.right - mainVP.left ;
  2415.             y = (float)( mainVP.top - mainVP.bottom ) / x ;
  2416.             x = 1.0f ;
  2417.         }
  2418.  
  2419.         pfPushIdentMatrix() ;
  2420.         ortho2( -x, x, -y, y ) ;
  2421.         cpack( 0x0 ) ;
  2422.         clear() ;
  2423.         cpack( 0x00ff ) ;
  2424.         positionText( -0.5f * getStrWidth( helvFont, msg ), 0.0f ) ;
  2425.         drawString( helvFont, msg ) ;
  2426.         pfPopMatrix() ;
  2427.     }
  2428.     else
  2429.     {
  2430.         drawStaticDisplay() ;
  2431.     }
  2432.     zfunction( ZF_LEQUAL ) ;
  2433.     zwritemask( 0xffffffff ) ;
  2434.  
  2435.     pfPopState();
  2436. }
  2437.  
  2438.  
  2439.  
  2440. /*------------------------------------------------------------------------------
  2441.  * Draw static on the screen.
  2442.  *----------------------------------------------------------------------------*/
  2443. static void
  2444. drawStaticDisplay(
  2445.     void
  2446.     )
  2447. {
  2448.     static int    cIndex = 0 ;
  2449.     static int    pIndex = 0 ;
  2450.     int        i ;
  2451.     float        dy = 0.3f ;
  2452.     float        y ;
  2453.     pfVec2        l ;
  2454.     pfVec2        r ;
  2455.  
  2456.     pfPushIdentMatrix() ;
  2457.     ortho2( 0.0f, 1.0f, 0.0f, 1.0f ) ;
  2458.     cpack( 0x00ff ) ;
  2459.     clear() ;
  2460.     y = -dy - 0.1f - ( rand() % 3 ) * 0.05 ;
  2461.     pIndex = 0 ;
  2462.     while( y < 1.0f )
  2463.     {
  2464.         for( i = 0 ; i < 3 ; i++ )
  2465.         {
  2466.             cIndex = ( cIndex + 1 ) % 3 ;
  2467.             pIndex = ( pIndex + 1 ) % 3 ;
  2468.             cpack( staticColor[cIndex] ) ;
  2469.             setpattern( STATIC_PATTERN_0 + pIndex ) ;
  2470.             bgntmesh() ;
  2471.                 PFSET_VEC2( l, 0.0f, y ) ;
  2472.                 PFSET_VEC2( r, 1.0f, y + dy ) ;
  2473.                 v2f( l ) ;
  2474.                 v2f( r ) ;
  2475.                 PFSET_VEC2( l, 0.0f, y + 0.1f ) ;
  2476.                 PFSET_VEC2( r, 1.0f, y + 0.1f + dy ) ;
  2477.                 v2f( l ) ;
  2478.                 v2f( r ) ;
  2479.             endtmesh() ;
  2480.         }
  2481.         cIndex = ( cIndex + 1 ) % 3 ;
  2482.         y += 0.1f ;
  2483.     }
  2484.     setpattern( 0 ) ;
  2485.  
  2486.     cIndex = ( cIndex + 1 + rand() % 2 ) % 3 ;
  2487.     pIndex = ( pIndex + 2 ) % 3 ;
  2488.  
  2489.     pfPopMatrix() ;
  2490. }
  2491.  
  2492.  
  2493.  
  2494. /*------------------------------------------------------------------------------
  2495.  * The demo main loop.
  2496.  *----------------------------------------------------------------------------*/
  2497. static void
  2498. demoMainLoop(
  2499.     void
  2500.     )
  2501. {
  2502.     float        lastTime ;
  2503.     static float    alarmTime = 0.0f ;
  2504.  
  2505.     while( stayInProgram )
  2506.     {
  2507.         while( selfStatus == OORT_ST_ON_GROUND )
  2508.         {
  2509.             /* Go to sleep till next frame time */
  2510.             pfSync() ;
  2511.  
  2512.             gameTime = pfGetTime() ;
  2513.             eTime = gameTime - lastTime ;
  2514.             lastTime = gameTime ;
  2515.  
  2516.             if( shields < 0.25f && gameTime - alarmTime > 2.0f )
  2517.             {
  2518.                 alarmTime = gameTime ;
  2519.                 sfx( SFX_ALARM ) ;
  2520.             }
  2521.  
  2522.             getLatLong() ;
  2523.  
  2524.             writePackets() ;
  2525.             readPackets() ;
  2526.  
  2527.             updateViewGround() ;
  2528.  
  2529.             distributePower() ;
  2530.  
  2531.             pfFrame();
  2532.  
  2533.             demoPostProcessPlayers() ;
  2534.         }
  2535.  
  2536.         while( selfStatus == OORT_ST_IN_ORBIT )
  2537.         {
  2538.             /* Go to sleep till next frame time */
  2539.             pfSync() ;
  2540.  
  2541.             gameTime = pfGetTime() ;
  2542.             eTime = gameTime - lastTime ;
  2543.             lastTime = gameTime ;
  2544.  
  2545.             writePackets() ;
  2546.             readPackets() ;
  2547.  
  2548.             updateViewInOrbit() ;
  2549.  
  2550.             pfFrame();
  2551.  
  2552.             demoPostProcessPlayers() ;
  2553.         }
  2554.  
  2555.         while( selfStatus == OORT_ST_DEAD )
  2556.         {
  2557.             /* Go to sleep till next frame time */
  2558.             pfSync() ;
  2559.  
  2560.             gameTime = pfGetTime() ;
  2561.             eTime = gameTime - lastTime ;
  2562.             lastTime = gameTime ;
  2563.  
  2564.             writePackets() ;
  2565.             readPackets() ;
  2566.  
  2567.             updateViewGround() ;
  2568.  
  2569.             pfFrame();
  2570.  
  2571.             demoPostProcessPlayers() ;
  2572.  
  2573.             if( gameTime - deadTime[SELF] > 5.0f )
  2574.             {
  2575.                 reset() ;
  2576.             }
  2577.             else
  2578.             {
  2579.                 power = ( gameTime - deadTime[SELF] ) / 5.0f ;
  2580.             }
  2581.         }
  2582.  
  2583.         while( selfStatus == OORT_ST_CONFIGURING )
  2584.         {
  2585.             /* Go to sleep till next frame time */
  2586.             pfSync() ;
  2587.  
  2588.             gameTime = pfGetTime() ;
  2589.             eTime = gameTime - lastTime ;
  2590.             lastTime = gameTime ;
  2591.  
  2592.             writePackets() ;
  2593.             readPackets() ;
  2594.  
  2595.             pfFrame();
  2596.  
  2597.             demoPostProcessPlayers() ;
  2598.         }
  2599.     }
  2600. }
  2601.  
  2602.  
  2603.  
  2604. /*------------------------------------------------------------------------------
  2605.  * Comparison function for sorting scores.
  2606.  *----------------------------------------------------------------------------*/
  2607. static int
  2608. compareScores(
  2609.     const void    *p1,
  2610.     const void    *p2
  2611.     )
  2612. {
  2613.     int    i1 = *(int *)p1 ;
  2614.     int    i2 = *(int *)p2 ;
  2615.  
  2616.     if( player[i1].score < player[i2].score )
  2617.         return( 1 ) ;
  2618.     else if( player[i1].score > player[i2].score )
  2619.         return( -1 ) ;
  2620.     else
  2621.         return( 0 ) ;
  2622. }
  2623.  
  2624.  
  2625.  
  2626. /*------------------------------------------------------------------------------
  2627.  * Show scores.
  2628.  *----------------------------------------------------------------------------*/
  2629. void
  2630. listScores(
  2631.     void
  2632.     )
  2633. {
  2634.     int    i ;
  2635.     int    n ;
  2636.     int    place ;
  2637.     int    p[MAXPLAYERS] ;
  2638.  
  2639.     if( nTextLines < 4 )
  2640.     {
  2641.         postNewMessage( "Not enough text lines." ) ;
  2642.         return ;
  2643.     }
  2644.  
  2645.     for( i = 0 ; i < numberPlayers ; i++ )
  2646.     {
  2647.         p[i] = i ;
  2648.     }
  2649.  
  2650.     qsort( (void *)p, numberPlayers, sizeof( p[0] ), compareScores ) ;
  2651.  
  2652.     place = 0 ;
  2653.     for( i = 0 ; i < numberPlayers ; i++ )
  2654.     {
  2655.         if( p[i] == SELF )
  2656.         {
  2657.             place = i + 1 ;
  2658.             break ;
  2659.         }
  2660.     }
  2661.  
  2662.     n = nTextLines - 3 ;
  2663.     if( n > numberPlayers )
  2664.     {
  2665.         n = numberPlayers ;
  2666.     }
  2667.     postNewMessage( "Your score: %d (%d of %d)", player[SELF].score,
  2668.             place, numberPlayers ) ;
  2669.     postNewMessage( "Top %d scores:", n ) ;
  2670.  
  2671.     for( i = 0 ; i < n ; i++ )
  2672.     {
  2673.         postNewMessage( "%-12s %3d", player[p[i]].name,
  2674.             player[p[i]].score ) ;
  2675.     }
  2676. }
  2677.  
  2678.  
  2679.  
  2680. /*------------------------------------------------------------------------------
  2681.  * No config file was found, so launch showcase help and create a default
  2682.  * config file in the home directory.
  2683.  *----------------------------------------------------------------------------*/
  2684. static void
  2685. noConfigFile(
  2686.     char    *name
  2687.     )
  2688. {
  2689.     int    i ;
  2690.     FILE    *f ;
  2691.  
  2692.     if( ( f = fopen( name, "w" ) ) == NULL )
  2693.     {
  2694.         perror( name ) ;
  2695.         fprintf( stderr, "%s: could not create default configuration "
  2696.             "file.\n", basename ) ;
  2697.     }
  2698.     else
  2699.     {
  2700.         for( i = 0 ; i < 6 ; i++ )
  2701.         {
  2702.             fputs( defaultConfigText[i], f ) ;
  2703.         }
  2704.  
  2705.         fclose( f ) ;
  2706.  
  2707.         fprintf( stderr, "%s: created %s.\n", basename, name ) ;
  2708.     }
  2709.  
  2710.     displayHelp() ;
  2711. }
  2712.  
  2713.  
  2714.  
  2715. /*------------------------------------------------------------------------------
  2716.  * Show the showcase help cards.
  2717.  *----------------------------------------------------------------------------*/
  2718. static void
  2719. displayHelp(
  2720.     void
  2721.     )
  2722. {
  2723.     char        *helpFile ;
  2724.     char        *cmd ;
  2725.     static int    seen = 0 ;
  2726.  
  2727.     if( seen == 1 )
  2728.         return ;
  2729.  
  2730.     seen = 1 ;
  2731.  
  2732.     helpFile = findFile( "oort_help.showcase" ) ;
  2733.  
  2734.     if( ( cmd = malloc( strlen( helpFile ) + 20 ) ) == NULL )
  2735.     {
  2736.         fprintf( stderr, "%s: out of memory -- could not start help "
  2737.             "file.\n", basename ) ;
  2738.     }
  2739.     else if( access( helpFile, R_OK ) == 0 )
  2740.     {
  2741.         if( getgdesc( GD_BITS_NORM_DBL_RED ) < 4 )
  2742.         {
  2743.             sprintf( cmd, "showcase -b -f -v %s", helpFile ) ;
  2744.         }
  2745.         else
  2746.         {
  2747.             sprintf( cmd, "showcase -f -v %s", helpFile ) ;
  2748.         }
  2749.         system( cmd ) ;
  2750.         free( cmd ) ;
  2751.     }
  2752.     else
  2753.     {
  2754.         perror( helpFile ) ;
  2755.     }
  2756.  
  2757.     free( helpFile ) ;
  2758. }
  2759.  
  2760.  
  2761.  
  2762. static char    *helpLine[] = {
  2763.             "Help Summary",
  2764.             "ESCAPE - exit game",
  2765.             "a/z - unzoom/zoom radar",
  2766.             "uparrow - increase volume",
  2767.             "downarrow - decrease volume",
  2768.             "s - show score",
  2769.             "h - toggle help screen",
  2770.             "i - show config info",
  2771.             "m - send broadcast message",
  2772.             "t - send team message",
  2773.             "f1 - show performance stats",
  2774.             "f2 - toggle terrain texture",
  2775.             "",
  2776.             "IN ORBIT",
  2777.             "leftmouse - pick landing site",
  2778.             "middlemouse - rotate Oort",
  2779.             "",
  2780.             "ON GROUND",
  2781.             "leftmouse - fire laser",
  2782.             "rightmouse - identify player",
  2783.             "space - apply brakes",
  2784.             "r - positive acceleration",
  2785.             "e - small positive acceleration",
  2786.             "w - small negative acceleration",
  2787.             "q - negative acceleration",
  2788.             "b - start/stop self destruct",
  2789.             "c - toggle ECM",
  2790.             "l - print lat/long location",
  2791.             } ;
  2792.  
  2793. /*------------------------------------------------------------------------------
  2794.  * Make object for displaying text.
  2795.  *----------------------------------------------------------------------------*/
  2796. static Object
  2797. makeHelpOverlay(
  2798.     void
  2799.     )
  2800. {
  2801.     int    i ;
  2802.     int    nLines ;
  2803.     Object    objectNo ;
  2804.     float    fontSize ;
  2805.     float    y ;
  2806.  
  2807.     objectNo = genobj() ;
  2808.  
  2809.     nLines = sizeof( helpLine ) / sizeof( helpLine[0] ) ;
  2810.     helpFont = copyFont( helvFont ) ;
  2811.     fontSize = 2.0f / ( nLines + 3 ) ;
  2812.  
  2813.     y = 1.0f - 2.0f * fontSize ;
  2814.     makeobj( objectNo ) ;
  2815.         setFontSize( helpFont, 1.5f * fontSize ) ;
  2816.         positionText( -0.5f * getStrWidth( helpFont, helpLine[0] ), y );
  2817.         drawString( helpFont, helpLine[0] ) ;
  2818.         y -= 2.0f * fontSize ;
  2819.         setFontSize( helpFont, fontSize ) ;
  2820.         for( i = 1 ; i < nLines ; i++ )
  2821.         {
  2822.             positionText( -0.5f *
  2823.                 getStrWidth( helpFont, helpLine[i] ), y ) ;
  2824.             drawString( helpFont, helpLine[i] ) ;
  2825.             y -= fontSize ;
  2826.         }
  2827.     closeobj() ;
  2828.  
  2829.     return( objectNo ) ;
  2830. }
  2831.  
  2832.  
  2833.  
  2834. /*------------------------------------------------------------------------------
  2835.  * Check for minimum system requirements.
  2836.  *----------------------------------------------------------------------------*/
  2837. static void
  2838. checkMinReqs(
  2839.     void
  2840.     )
  2841. {
  2842.     /*
  2843.      * Make sure we have a z-buffer and can run in RGB mode.
  2844.      */
  2845.     if( getgdesc( GD_BITS_NORM_ZBUFFER ) == 0 )
  2846.     {
  2847.         fprintf( stderr, "%s: no z-buffer available.\n", basename ) ;
  2848.         exit( 1 ) ;
  2849.     }
  2850.  
  2851.     /*
  2852.      * Make sure we can run in RGB mode.
  2853.      */
  2854.     if( getgdesc( GD_BITS_NORM_DBL_RED ) == 0  ||
  2855.         getgdesc( GD_BITS_NORM_DBL_GREEN ) == 0 ||
  2856.         getgdesc( GD_BITS_NORM_DBL_BLUE ) == 0 )
  2857.     {
  2858.         fprintf( stderr, "%s: double-buffer RGB mode not supported.\n",
  2859.             basename ) ;
  2860.         exit( 1 ) ;
  2861.     }
  2862. }
  2863.  
  2864.  
  2865.  
  2866. /*------------------------------------------------------------------------------
  2867.  * Discriminator callback function for intersections.
  2868.  *----------------------------------------------------------------------------*/
  2869. static long
  2870. pickDiscFunc(
  2871.     pfHit    *hit
  2872.     )
  2873. {
  2874.     if( checkTrike > 0 )
  2875.     {
  2876.         trikeHit = checkTrike ;
  2877.     }
  2878.  
  2879.     return( PFTRAV_CONT | PFTRAV_IS_CLIP_END ) ;
  2880. }
  2881.  
  2882.  
  2883.  
  2884. /*------------------------------------------------------------------------------
  2885.  * Replacement function for pfChanPick -- does a pfSegsIsectNode on the
  2886.  * main channel from the eye position through the cursor position.
  2887.  *----------------------------------------------------------------------------*/
  2888. static void
  2889. doPick(
  2890.     pfNode    *root,
  2891.     long    mode,
  2892.     long    mask,
  2893.     pfHit    **hits[]
  2894.     )
  2895. {
  2896.     pfVec3        eye ;
  2897.     pfVec3        ll ;
  2898.     pfVec3        lr ;
  2899.     pfVec3        ul ;
  2900.     pfVec3        ur ;
  2901.     pfVec3        v ;
  2902.     pfVec3        h ;
  2903.     pfSegSet    segSet ;
  2904.     pfSeg        iSegs[1] ;
  2905.  
  2906.     pfGetFrustEye( mainChan, eye ) ;
  2907.     pfGetFrustFar( mainChan, ll, lr, ul, ur ) ;
  2908.     PFSUB_VEC3( v, lr, ll ) ;
  2909.     ADDSCALE_VEC3( v, ll, pickX, v ) ;
  2910.     PFSUB_VEC3( h, ul, ll ) ;
  2911.     ADDSCALE_VEC3( v, v, pickY, h ) ;
  2912.     pfMakePtsSeg( &(segSet.segs[0]), eye, v ) ;
  2913.     segSet.activeMask = 0x01 ;
  2914.     segSet.mode = mode ;
  2915.     segSet.isectMask = mask ;
  2916.     segSet.bound = NULL ;
  2917.     segSet.discFunc = NULL ;
  2918.     segSet.userData = NULL ;
  2919.     segSet.discFunc = pickDiscFunc ;
  2920.  
  2921.     pfSegsIsectNode( root, &segSet, hits ) ;
  2922. }
  2923.  
  2924.  
  2925.  
  2926. /*------------------------------------------------------------------------------
  2927.  * Initialize the shield geometries.
  2928.  *----------------------------------------------------------------------------*/
  2929. static void
  2930. initShield(
  2931.     void
  2932.     )
  2933. {
  2934.     int    i ;
  2935.  
  2936.     if( ( shield = loadOortShield( "shield.data" ) ) == NULL )
  2937.     {
  2938.         endProgram( 1 ) ;
  2939.     }
  2940.  
  2941.     if( ( vehicleBoundingSphere = myMalloc( sizeof( pfSphere ) ) ) == NULL )
  2942.     {
  2943.         endProgram( 1 ) ;
  2944.     }
  2945.         
  2946.     PFSET_VEC3( vehicleBoundingSphere->center, 0.0f, 0.0f, 0.0f ) ;
  2947.     vehicleBoundingSphere->radius = 2.5f ;
  2948.  
  2949.     pfNodeBSphere( shield, vehicleBoundingSphere,
  2950.             PFN_BMODE_STATIC ) ;
  2951.  
  2952.     for( i = 0 ; i < N_TEAMS ; i++ )
  2953.     {
  2954.         pfNodeBSphere( vehicle[i], vehicleBoundingSphere,
  2955.                 PFN_BMODE_STATIC ) ;
  2956.     }
  2957. }
  2958.  
  2959.  
  2960.  
  2961. /*------------------------------------------------------------------------------
  2962.  * Draw laser strikes from obital fortresses.
  2963.  *----------------------------------------------------------------------------*/
  2964. static void
  2965. drawOrbitalFortressStrikes(
  2966.     void
  2967.     )
  2968. {
  2969.     int    i ;
  2970.     pfVec3    top ;
  2971.  
  2972.     for( i = ENEMY ; i < numberPlayers ; i++ )
  2973.     {
  2974.         if( player[i].status & OORT_ST_IDLE_HIT )
  2975.         {
  2976.             PFSCALE_VEC3( top, 3.0f, player[i].xyz ) ;
  2977.             cpack( 0x0000ff00 ) ;
  2978.             bgnline() ;
  2979.                 v3f( top ) ;
  2980.                 v3f( player[i].xyz ) ;
  2981.             endline() ;
  2982.             player[i].status &= ~OORT_ST_IDLE_HIT ;
  2983.         }
  2984.     }
  2985. }
  2986.  
  2987.  
  2988.  
  2989. /*------------------------------------------------------------------------------
  2990.  * Draw title screen.
  2991.  *----------------------------------------------------------------------------*/
  2992. static void
  2993. drawTitle(
  2994.     void
  2995.     )
  2996. {
  2997.     float        x ;
  2998.     float        y ;
  2999.     Screencoord    l ;
  3000.     Screencoord    r ;
  3001.     Screencoord    b ;
  3002.     Screencoord    t ;
  3003.     static GeoFont    *tf = NULL ;
  3004.     static char    *title = "OORT" ;
  3005.     static char    *version = "1.1" ;
  3006.     static char    *motd = "See help screen for key changes." ;
  3007.  
  3008.     pfPushIdentMatrix() ;
  3009.     reshapeviewport() ;
  3010.     getviewport( &l, &r, &b, &t ) ;
  3011.  
  3012.     zfunction( ZF_ALWAYS ) ;
  3013.         zwritemask( 0x0 ) ;
  3014.  
  3015.     if( tf == NULL )
  3016.     {
  3017.         tf = copyFont( helvFont ) ;
  3018.     }
  3019.  
  3020.     if( r - l > t - b )
  3021.     {
  3022.         y = t - b ;
  3023.         x = (float)( r - l ) / y ;
  3024.         y = 1.0f ;
  3025.     }
  3026.     else
  3027.     {
  3028.         x = r - mainVP.left ;
  3029.         y = (float)( t - b ) / x ;
  3030.         x = 1.0f ;
  3031.     }
  3032.  
  3033.     ortho2( -x, x, -y, y ) ;
  3034.     cpack( 0x0 ) ;
  3035.     clear() ;
  3036.     cpack( 0x00ff ) ;
  3037.     setFontSize( tf, 0.4f ) ;
  3038.     positionText( -0.5f * getStrWidth( tf, title ), 0.0f ) ;
  3039.     drawString( tf, title ) ;
  3040.     setFontSize( tf, 0.2f ) ;
  3041.     positionText( -0.5f * getStrWidth( tf, version ), -0.25f ) ;
  3042.     drawString( tf, version ) ;
  3043.     setFontSize( tf, 0.1f ) ;
  3044.     positionText( -0.5f * getStrWidth( tf, motd ), -0.375f ) ;
  3045.     drawString( tf, motd ) ;
  3046.  
  3047.     zfunction( ZF_LEQUAL ) ;
  3048.     zwritemask( 0xffffffff ) ;
  3049.  
  3050.     pfPopMatrix() ;
  3051. }
  3052.  
  3053.  
  3054.  
  3055. /*------------------------------------------------------------------------------
  3056.  * Toggle texturing on/off.
  3057.  *----------------------------------------------------------------------------*/
  3058. int
  3059. toggleTexturing(
  3060.     void
  3061.     )
  3062. {
  3063.     static mode = 1 ;
  3064.  
  3065.     if( terrainTextured )
  3066.     {
  3067.         if( mode )
  3068.         {
  3069.             pfDisable(PFEN_TEXTURE);
  3070.             pfOverride(PFSTATE_ENTEXTURE, PF_ON) ;
  3071.             postNewMessage( "Textures disabled." ) ;
  3072.             mode = 0 ;
  3073.         }
  3074.         else
  3075.         {
  3076.             pfEnable(PFEN_TEXTURE);
  3077.             pfOverride(PFSTATE_ENTEXTURE, PF_OFF) ;
  3078.             postNewMessage( "Textures enabled." ) ;
  3079.             mode = 1 ;
  3080.         }
  3081.     }
  3082.     else
  3083.     {
  3084.         postNewMessage( "No texture data available." ) ;
  3085.     }
  3086. }
  3087.  
  3088.  
  3089.  
  3090. /*------------------------------------------------------------------------------
  3091.  * Try to determine if hardware texturing is available.  This is really
  3092.  * cheesy because it will have to be updated when new hardware becomes
  3093.  * available.
  3094.  *----------------------------------------------------------------------------*/
  3095. static void
  3096. checkGraphicsHw( void )
  3097. {
  3098.     int    i ;
  3099.     int    doTex = 0 ;
  3100.     char    buf[64] ;
  3101.     static char    *texGraphicsHw[] = { "GTX", "VGX", "RE" } ;
  3102.  
  3103.     gversion( buf ) ;
  3104.  
  3105.     for( i = 0 ; i < sizeof( texGraphicsHw ) / sizeof( texGraphicsHw[0] ) ;
  3106.         i++ )
  3107.     {
  3108.         if( strstr( buf, texGraphicsHw[i] ) != NULL )
  3109.         {
  3110.             doTex = 1 ;
  3111.             break ;
  3112.         }
  3113.     }
  3114.  
  3115.     if( doTex == 0 )
  3116.     {
  3117.         toggleTexturing() ;
  3118.     }
  3119. }
  3120.  
  3121.